Subject: TCPCTL_IDENT (Was: CVS commit: src/etc)
To: None <tron@netbsd.org>
From: Simon Burge <simonb@wasabisystems.com>
List: tech-kern
Date: 05/02/2003 22:53:20
Matthias Scheler wrote:

> Module Name:	src
> Committed By:	tron
> Date:		Fri May  2 08:51:09 UTC 2003
> 
> Modified Files:
> 
> 	src/etc: inetd.conf
> 
> Log Message:
> 
> identd(8) must run as "root" to use TCPCTL_IDENT via sysctl(3). This fixes
> PR bin/21261 by myself.

IMHO this isn't the right fix; it's the TCPCTL_IDENT sysctl that is
broken.  The sysctl uses the newp arg to pass input to lookup the pcb
which is not how sysctl() is supposed to work.

The following patch changes the sysctl to using only the mib for the
query and works with "nobody:kmem" in /etc/inetd.conf.  Anyone see any
problems with this?

This would mean that if anyone has used the TCPCTL_IDENT in the last
month or so they'd now lose (both from an binary compatibility and API
point of view), but I'm willing to live with that :-)

Simon.
--
Simon Burge                            <simonb@wasabisystems.com>
NetBSD Support and Service:         http://www.wasabisystems.com/



Index: sys/netinet/tcp_usrreq.c
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_usrreq.c,v
retrieving revision 1.76
diff -d -p -u -r1.76 tcp_usrreq.c
--- sys/netinet/tcp_usrreq.c	2003/04/19 20:58:36	1.76
+++ sys/netinet/tcp_usrreq.c	2003/05/02 12:41:16
@@ -160,7 +160,7 @@ __KERNEL_RCSID(0, "$NetBSD: tcp_usrreq.c
  */
 extern	char *tcpstates[];
 
-static int tcp_sysctl_ident(void *, size_t *, void *, size_t);
+static int tcp_sysctl_ident(int *, u_int, void *, size_t *);
 
 /*
  * Process a TCP user request for TCP tb.  If this is a send request
@@ -945,13 +945,13 @@ tcp_sysctl(name, namelen, oldp, oldlenp,
 {
 	int error, saved_value = 0;
 
-	/* All sysctl names at this level are terminal. */
+	if (name[0] == TCPCTL_IDENT)
+		return tcp_sysctl_ident(name + 1, namelen - 1, oldp, oldlenp);
+
+	/* All remaining sysctl names at this level are terminal. */
 	if (namelen != 1)
 		return (ENOTDIR);
 
-	if (name[0] == TCPCTL_IDENT)
-		return tcp_sysctl_ident(oldp, oldlenp, newp, newlen);
-
 	if (name[0] < sizeof(tcp_ctlvars)/sizeof(tcp_ctlvars[0])
 	    && tcp_ctlvars[name[0]].valid) {
 		if (tcp_ctlvars[name[0]].rdonly) {
@@ -984,27 +984,25 @@ tcp_sysctl(name, namelen, oldp, oldlenp,
 
 
 static int 
-tcp_sysctl_ident(void *oldp, size_t *oldlenp, void *newp, size_t newlen)
+tcp_sysctl_ident(int *name, u_int namelen, void *oldp, size_t *oldlenp)
 {
-	struct sysctl_tcp_ident_args args;
+	struct in_addr from, local;
 	struct socket *sockp;
 	struct inpcb *inb;
 	uid_t uid;
 	int error;
 
-	if (newlen != sizeof(args))
-		return EINVAL;
-	if (!newp)
-		return EFAULT;
+	if (namelen != 4)
+		return (EINVAL);
+
 	if (*oldlenp != sizeof(uid_t))
 		return ENOMEM;
 	if (!oldp || *oldlenp != sizeof(uid_t))
 		return ENOMEM;
-	if ((error = copyin(newp, &args, newlen)) != 0)
-		return error;
 	
-	inb = in_pcblookup_connect(&tcbtable, args.raddr, args.rport,
-	    args.laddr, args.lport);
+	from.s_addr = name[0];
+	local.s_addr = name[2];
+	inb = in_pcblookup_connect(&tcbtable, from, name[1], local, name[3]);
 	if (inb) {
 		sockp = inb->inp_socket;
 		if (sockp)
Index: sys/netinet/tcp_var.h
===================================================================
RCS file: /cvsroot/src/sys/netinet/tcp_var.h,v
retrieving revision 1.97
diff -d -p -u -r1.97 tcp_var.h
--- sys/netinet/tcp_var.h	2003/04/19 20:58:35	1.97
+++ sys/netinet/tcp_var.h	2003/05/02 12:41:17
@@ -622,15 +622,8 @@ struct	tcpstat {
 	{ "rstppslimit", CTLTYPE_INT }, \
 	{ "delack_ticks", CTLTYPE_INT }, \
 	{ "init_win_local", CTLTYPE_INT }, \
-	{ "ident", CTLTYPE_STRUCT }, \
+	{ "ident", CTLTYPE_INT }, \
 }
-
-struct sysctl_tcp_ident_args {
-	struct in_addr raddr;
-	u_int rport;
-	struct in_addr laddr;
-	u_int lport;
-};
 
 #ifdef _KERNEL
 extern	struct inpcbtable tcbtable;	/* head of queue of active tcpcb's */
Index: libexec/identd/netbsd.c
===================================================================
RCS file: /cvsroot/src/libexec/identd/netbsd.c,v
retrieving revision 1.17
diff -d -p -u -r1.17 netbsd.c
--- libexec/identd/netbsd.c	2003/04/22 16:42:00	1.17
+++ libexec/identd/netbsd.c	2003/05/02 12:41:17
@@ -89,10 +89,9 @@ int k_getuid(faddr, fport, laddr, lport,
   char **cmd, **cmd_and_args;
 #endif
 {
-  int mib[4];
+  int mib[8];
   uid_t myuid = -1;
   size_t uidlen;
-  struct sysctl_tcp_ident_args args;
   int rv;
   
   mib[0] = CTL_NET;
@@ -100,16 +99,16 @@ int k_getuid(faddr, fport, laddr, lport,
   mib[2] = IPPROTO_TCP;
   mib[3] = TCPCTL_IDENT;
 
-  args.raddr = *faddr;
-  args.rport = fport;
-  args.laddr = *laddr;
-  args.lport = lport;
+  mib[4] = (int) faddr->s_addr;
+  mib[5] = fport;
+  mib[6] = (int) laddr->s_addr;
+  mib[7] = lport;
 
   uidlen = sizeof(myuid);
   
-    if ((rv = sysctl(mib, 4, &myuid, &uidlen, &args,sizeof(args))) < 0)
+    if ((rv = sysctl(mib, 8, &myuid, &uidlen, NULL, NULL)) < 0)
     {
-      ERROR1("k_getuid: sysctl 1: %s", strerror(errno));
+      ERROR1("k_getuid: sysctl(TCPCTL_IDENT): %s", strerror(errno));
       return -1;
     }