From owner-freebsd-bugs Sat May 1 21:20:17 1999 Delivered-To: freebsd-bugs@freebsd.org Received: from freefall.freebsd.org (freefall.FreeBSD.ORG [204.216.27.21]) by hub.freebsd.org (Postfix) with ESMTP id 1A7B314D6D for ; Sat, 1 May 1999 21:20:02 -0700 (PDT) (envelope-from gnats@FreeBSD.org) Received: (from gnats@localhost) by freefall.freebsd.org (8.9.3/8.9.2) id VAA37948; Sat, 1 May 1999 21:20:01 -0700 (PDT) (envelope-from gnats@FreeBSD.org) Received: from janus.syracuse.net (janus.syracuse.net [205.232.47.15]) by hub.freebsd.org (Postfix) with ESMTP id 3D00814C99 for ; Sat, 1 May 1999 21:17:24 -0700 (PDT) (envelope-from green@unixhelp.org) Received: from localhost (green@localhost) by janus.syracuse.net (8.9.2/8.8.7) with ESMTP id AAA67340 for ; Sun, 2 May 1999 00:17:28 -0400 (EDT) Message-Id: Date: Sun, 2 May 1999 00:17:28 -0400 (EDT) From: Brian Feldman To: freebsd-gnats-submit@freebsd.org Subject: kern/11435: IPFW uid/gid support Sender: owner-freebsd-bugs@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org >Number: 11435 >Category: kern >Synopsis: IPFW had no per-uid or per-gid rule support. >Confidential: no >Severity: serious >Priority: medium >Responsible: freebsd-bugs >State: open >Quarter: >Keywords: >Date-Required: >Class: change-request >Submitter-Id: current-users >Arrival-Date: Sat May 1 21:20:01 PDT 1999 >Closed-Date: >Last-Modified: >Originator: Brian Feldman >Release: FreeBSD 4.0-CURRENT i386 >Organization: >Environment: I use 4.0-CURRENT. The code should backport easily to 3.X. >Description: I've added IPFW uid and gid rule options. This will work for filtering packets for both TCP and UDP. Since these are the two IP user-controlled protocols, and most useful anyway. The only other common Internet protocol would be ICMP, which is not a user protocol anyway. >How-To-Repeat: This doesn't apply, does it? >Fix: --- src/sbin/ipfw/ipfw.c.orig Thu Jan 21 20:46:32 1999 +++ src/sbin/ipfw/ipfw.c Wed Apr 21 07:41:03 1999 @@ -30,8 +30,10 @@ #include #include #include +#include #include #include +#include #include #include #include @@ -333,6 +335,24 @@ } } + if (chain->fw_flg & IP_FW_F_UID) { + struct passwd *pwd = getpwuid(chain->fw_uid); + + if (pwd) + printf(" uid %s", pwd->pw_name); + else + printf(" uid %u", chain->fw_uid); + } + + if (chain->fw_flg & IP_FW_F_GID) { + struct group *grp = getgrgid(chain->fw_gid); + + if (grp) + printf(" gid %s", grp->gr_name); + else + printf(" gid %u", chain->fw_gid); + } + /* Direction */ if ((chain->fw_flg & IP_FW_F_IN) && !(chain->fw_flg & IP_FW_F_OUT)) printf(" in"); @@ -586,6 +606,8 @@ " src: from [not] {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n" " dst: to [not] {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n" " extras:\n" +" uid {user id}\n" +" gid {group id}\n" " fragment (may not be used with ports or tcpflags)\n" " in\n" " out\n" @@ -1185,6 +1207,32 @@ } while (ac) { + if (!strncmp(*av,"uid",strlen(*av))) { + struct passwd *pwd; + + rule.fw_flg |= IP_FW_F_UID; + ac--; av++; + if (!ac) + show_usage("``uid'' requires argument"); + + rule.fw_uid = (pwd = getpwnam(*av)) ? pwd->pw_uid + : strtoul(*av, NULL, 0); + ac--; av++; + continue; + } + if (!strncmp(*av,"gid",strlen(*av))) { + struct group *grp; + + rule.fw_flg |= IP_FW_F_GID; + ac--; av++; + if (!ac) + show_usage("``gid'' requires argument"); + + rule.fw_gid = (grp = getgrnam(*av)) ? (gid_t)grp->gr_gid + : strtoul(*av, NULL, 0); + ac--; av++; + continue; + } if (!strncmp(*av,"in",strlen(*av))) { rule.fw_flg |= IP_FW_F_IN; av++; ac--; continue; --- src/sys/sys/socketvar.h.orig Tue Apr 20 23:27:58 1999 +++ src/sys/sys/socketvar.h Tue Apr 20 23:27:15 1999 @@ -109,6 +109,7 @@ /* NB: generation count must not be first; easiest to make it last. */ so_gen_t so_gencnt; /* generation count */ void *so_emuldata; /* private data for emulators */ + struct pcred *so_cred; /* user credentials */ }; /* --- src/sys/kern/uipc_socket.c.orig Tue Apr 20 23:30:54 1999 +++ src/sys/kern/uipc_socket.c Wed Apr 21 00:52:03 1999 @@ -36,13 +36,14 @@ #include #include -#include #include #include #include #include #include +#include #include +#include #include #include #include @@ -124,8 +125,11 @@ TAILQ_INIT(&so->so_incomp); TAILQ_INIT(&so->so_comp); so->so_type = type; - if (p != 0) + if (p != 0) { so->so_uid = p->p_ucred->cr_uid; + so->so_cred = p->p_cred; + p->p_cred->p_refcnt++; + } else so->so_cred = NULL; so->so_proto = prp; error = (*prp->pr_usrreqs->pru_attach)(so, proto, p); if (error) { @@ -156,6 +160,10 @@ struct socket *so; { so->so_gencnt = ++so_gencnt; + if (so->so_cred && --so->so_cred->p_refcnt == 0) { + crfree(so->so_cred->pc_ucred); + FREE(so->so_cred, M_SUBPROC); + } zfreei(so->so_zone, so); } --- src/sys/kern/uipc_socket2.c.orig Tue Apr 20 23:31:08 1999 +++ src/sys/kern/uipc_socket2.c Wed Apr 21 00:46:18 1999 @@ -214,6 +214,10 @@ so->so_proto = head->so_proto; so->so_timeo = head->so_timeo; so->so_uid = head->so_uid; + if (head->so_cred) { + so->so_cred = head->so_cred; + so->so_cred->p_refcnt++; + } else so->so_cred = NULL; (void) soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat); if ((*so->so_proto->pr_usrreqs->pru_attach)(so, 0, NULL)) { --- src/sys/netinet/ip_fw.c.orig Tue Apr 20 10:29:59 1999 +++ src/sys/netinet/ip_fw.c Wed Apr 21 00:20:50 1999 @@ -34,18 +34,21 @@ #include #include #include +#include #include #include #include +#include #include +#include #include #include +#include #include #include #include #include #ifdef DUMMYNET -#include #include #endif #include @@ -53,6 +56,7 @@ #include #include #include +#include #include /* XXX ethertype_ip */ @@ -608,13 +612,14 @@ if (f->fw_ipopt != f->fw_ipnopt && !ipopts_match(ip, f)) continue; - /* Check protocol; if wildcard, match */ - if (f->fw_prot == IPPROTO_IP) - goto got_match; - - /* If different, don't match */ - if (ip->ip_p != f->fw_prot) - continue; + /* Check protocol; if wildcard, and no uid, match */ + if (f->fw_prot == IPPROTO_IP) { + if (!(f->fw_flg & (IP_FW_F_UID|IP_FW_F_GID))) + goto got_match; + } else + /* If different, don't match */ + if (ip->ip_p != f->fw_prot) + continue; /* * here, pip==NULL for bridged pkts -- they include the ethernet @@ -634,6 +639,88 @@ } \ } while (0) + /* Protocol specific checks for uid only */ + if (f->fw_flg & (IP_FW_F_UID|IP_FW_F_GID)) { + switch (ip->ip_p) { + case IPPROTO_TCP: + { + struct tcphdr *tcp; + struct inpcb *P; + + if (offset == 1) /* cf. RFC 1858 */ + goto bogusfrag; + if (offset != 0) + continue; + + PULLUP_TO(hlen + 14); + tcp =(struct tcphdr *)((u_int32_t *)ip + ip->ip_hl); + + if (oif) + P = in_pcblookup_hash(&tcbinfo, ip->ip_dst, + tcp->th_dport, ip->ip_src, tcp->th_sport, 0); + else + P = in_pcblookup_hash(&tcbinfo, ip->ip_src, + tcp->th_sport, ip->ip_dst, tcp->th_dport, 0); + + if (P && P->inp_socket && P->inp_socket->so_cred) { + if ((f->fw_flg & IP_FW_F_UID) && + P->inp_socket->so_cred->p_ruid != f->fw_uid) + continue; + if ((f->fw_flg & IP_FW_F_GID) && + !groupmember(f->fw_gid, + P->inp_socket->so_cred->pc_ucred)) + continue; + } else continue; + + break; + } + + case IPPROTO_UDP: + { + struct udphdr *udp; + struct inpcb *P; + + if (offset != 0) + continue; + + PULLUP_TO(hlen + 4); + udp =(struct udphdr *)((u_int32_t *)ip + ip->ip_hl); + + if (oif) + P = in_pcblookup_hash(&udbinfo, ip->ip_dst, + udp->uh_dport, ip->ip_src, udp->uh_sport, 1); + else + P = in_pcblookup_hash(&udbinfo, ip->ip_src, + udp->uh_sport, ip->ip_dst, udp->uh_dport, 1); + + if (P && P->inp_socket && P->inp_socket->so_cred) { + if ((f->fw_flg & IP_FW_F_UID) && + P->inp_socket->so_cred->p_ruid != f->fw_uid) + continue; + if ((f->fw_flg & IP_FW_F_GID) && + !groupmember(f->fw_gid, + P->inp_socket->so_cred->pc_ucred)) + continue; + } else continue; + + break; + } + + default: + continue; +/* + * XXX Shouldn't GCC be allowing two bogusfrag labels if they're both inside + * separate blocks? Hmm.... It seems it's got incorrect behavior here. + */ +#if 0 +bogusfrag: + if (fw_verbose) + ipfw_report(NULL, ip, rif, oif); + goto dropit; +#endif + } + } + /* Protocol specific checks */ switch (ip->ip_p) { case IPPROTO_TCP: @@ -654,7 +741,8 @@ break; } - PULLUP_TO(hlen + 14); + if (!(f->fw_flg & (IP_FW_F_UID|IP_FW_F_GID))) + PULLUP_TO(hlen + 14); tcp = (struct tcphdr *) ((u_int32_t *)ip + ip->ip_hl); if (f->fw_tcpf != f->fw_tcpnf && !tcpflg_match(tcp, f)) continue; @@ -673,12 +761,13 @@ * rule specifies a port, we consider the rule * a non-match. */ - if (f->fw_nports != 0) + if (f->fw_nports) continue; break; } - PULLUP_TO(hlen + 4); + if (!(f->fw_flg & (IP_FW_F_UID|IP_FW_F_GID))) + PULLUP_TO(hlen + 4); udp = (struct udphdr *) ((u_int32_t *)ip + ip->ip_hl); src_port = ntohs(udp->uh_sport); dst_port = ntohs(udp->uh_dport); @@ -1121,6 +1210,8 @@ #ifdef IPFIREWALL_FORWARD case IP_FW_F_FWD: #endif + case IP_FW_F_UID: + case IP_FW_F_GID: break; default: dprintf(("%s invalid command\n", err_prefix)); --- src/sys/netinet/ip_fw.h.orig Tue Apr 20 09:32:05 1999 +++ src/sys/netinet/ip_fw.h Wed Apr 21 01:02:58 1999 @@ -81,6 +81,8 @@ /* count of 0 means match all ports) */ void *pipe_ptr; /* Pipe ptr in case of dummynet pipe */ void *next_rule_ptr ; /* next rule in case of match */ + uid_t fw_uid; /* uid to match */ + gid_t fw_gid; /* gid to match */ }; #define IP_FW_GETNSRCP(rule) ((rule)->fw_nports & 0x0f) @@ -144,7 +146,11 @@ #define IP_FW_F_ICMPBIT 0x00100000 /* ICMP type bitmap is valid */ -#define IP_FW_F_MASK 0x001FFFFF /* All possible flag bits mask */ +#define IP_FW_F_UID 0x00200000 /* filter by uid */ + +#define IP_FW_F_GID 0x00400000 /* filter by uid */ + +#define IP_FW_F_MASK 0x007FFFFF /* All possible flag bits mask */ /* * For backwards compatibility with rules specifying "via iface" but --- src/sys/netinet/udp_var.h.orig Sun Apr 4 22:47:21 1999 +++ src/sys/netinet/udp_var.h Sun Apr 4 22:50:44 1999 @@ -103,6 +103,7 @@ SYSCTL_DECL(_net_inet_udp); extern struct pr_usrreqs udp_usrreqs; +extern struct inpcbinfo udbinfo; void udp_ctlinput __P((int, struct sockaddr *, void *)); void udp_init __P((void)); --- src/sys/netinet/udp_usrreq.c.orig Sun Apr 4 22:51:26 1999 +++ src/sys/netinet/udp_usrreq.c Sun Apr 4 22:51:31 1999 @@ -78,7 +78,7 @@ &log_in_vain, 0, ""); static struct inpcbhead udb; /* from udp_var.h */ -static struct inpcbinfo udbinfo; +struct inpcbinfo udbinfo; #ifndef UDBHASHSIZE #define UDBHASHSIZE 16 --- src/sbin/ipfw/ipfw.8.orig Fri Apr 23 22:26:55 1999 +++ src/sbin/ipfw/ipfw.8 Fri Apr 23 22:37:04 1999 @@ -258,6 +258,18 @@ The search continues with the first rule numbered .Ar number or higher. +.It Ar uid user +Match all TCP or UDP packets sent by or received for a +.Ar user . +A +.Ar user +may be matched by name or identification number. +.It Ar gid group +Match all TCP or UDP packets sent by or received for a +.Ar group . +A +.Ar group +may be matched by name or identification number. .El .Pp If a packet matches more than one >Release-Note: >Audit-Trail: >Unformatted: To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-bugs" in the body of the message