Date: Sat, 29 May 1999 01:20:44 -0400 (EDT) From: Brian Feldman <green@unixhelp.org> To: hackers@freebsd.org Subject: proposed socket change (IPFW too? :) Message-ID: <Pine.BSF.4.10.9905290052410.77444-100000@janus.syracuse.net>
next in thread | raw e-mail | index | archive | help
I'd like to propose a change in struct socket, which should increase its functionality. It should first be noted that, along with my IPFW UID/GID code (which would be nice to have merged into HEAD too, and if I must, I'll clean up the ugly switch part), I included this change. Implementation time would be nil, as would testing. The change itself would be to store a pointer to struct pcred in each struct socket. The changes are already done, but I'd like to get rid of the so_uid too (if possible). Following the cred changes, I'd like to make a sysctl to find out a socket's credentials. After that, a decent identd to be shipped with FreeBSD (under the FreeBSD license, of course). How does all of this sound? I'm including the latest IPFW UID/GID patches, which have the so_cred functionality. Brian Feldman _ __ ___ ____ ___ ___ ___ green@unixhelp.org _ __ ___ | _ ) __| \ FreeBSD: The Power to Serve! _ __ | _ \ _ \ |) | http://www.freebsd.org _ |___)___/___/ --- 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 <ctype.h> #include <err.h> #include <errno.h> +#include <grp.h> #include <limits.h> #include <netdb.h> +#include <pwd.h> #include <signal.h> #include <stdio.h> #include <stdlib.h> @@ -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 */ }; /* --- uipc_socket.c.orig Fri May 28 17:19:58 1999 +++ uipc_socket.c Sat May 29 01:12:43 1999 @@ -36,13 +36,14 @@ #include <sys/param.h> #include <sys/systm.h> -#include <sys/proc.h> #include <sys/fcntl.h> #include <sys/malloc.h> #include <sys/mbuf.h> #include <sys/domain.h> #include <sys/kernel.h> +#include <sys/malloc.h> #include <sys/poll.h> +#include <sys/proc.h> #include <sys/protosw.h> #include <sys/socket.h> #include <sys/socketvar.h> @@ -124,8 +125,11 @@ TAILQ_INIT(&so->so_incomp); TAILQ_INIT(&so->so_comp); so->so_type = type; - if (p != 0) - so->so_uid = p->p_ucred->cr_uid; + if (p) { + so->so_cred = p->p_cred; + so->so_cred->p_refcnt++; + so->so_uid = so->so_cred->pc_ucred->cr_uid; + } 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); } --- uipc_socket2.c.orig Fri May 28 17:19:58 1999 +++ uipc_socket2.c Sat May 29 00:57:56 1999 @@ -214,6 +214,9 @@ so->so_proto = head->so_proto; so->so_timeo = head->so_timeo; so->so_uid = head->so_uid; + so->so_cred = head->so_cred; + if (so->so_cred) + so->so_cred->p_refcnt++; (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 <sys/malloc.h> #include <sys/mbuf.h> #include <sys/kernel.h> +#include <sys/proc.h> #include <sys/socket.h> #include <sys/socketvar.h> #include <sys/sysctl.h> +#include <sys/ucred.h> #include <net/if.h> +#include <net/route.h> #include <netinet/in.h> #include <netinet/in_systm.h> +#include <netinet/in_pcb.h> #include <netinet/ip.h> #include <netinet/ip_var.h> #include <netinet/ip_icmp.h> #include <netinet/ip_fw.h> #ifdef DUMMYNET -#include <net/route.h> #include <netinet/ip_dummynet.h> #endif #include <netinet/tcp.h> @@ -53,6 +56,7 @@ #include <netinet/tcp_var.h> #include <netinet/tcpip.h> #include <netinet/udp.h> +#include <netinet/udp_var.h> #include <netinet/if_ether.h> /* 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 To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-hackers" in the body of the message
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?Pine.BSF.4.10.9905290052410.77444-100000>