Subject: Re: SO_PEERNAME
To: None <tech-kern@netbsd.org>
From: der Mouse <mouse@Rodents.Montreal.QC.CA>
List: tech-kern
Date: 08/27/2001 02:38:48
Okay, I finally sat down with this.  I've now got patches that allow
you to set LOCAL_CREDS on a listening socket and get credentials passed
at connect() time, instead of having to wait for a data send.  While I
was experimenting, I noticed that if you want credentials on every data
send, there is presently no way to get them; you have to re-enable
LOCAL_CREDS after every send is done.  Unfortunately, the credential
passing happens at send time, not at receive time, so unless you're
blocking in a receive, there is no way to tell when a send happens.
And even if you are, there's a race between reenabling LOCAL_CREDS and
the next send.  So I added another option, LOCAL_CREDS_STICKY, which
means that if LOCAL_CREDS is set, it isn't cleared when a data send is
done.  (Of course, this will not normally be used; it's of use only
when data sends by differently-credentialed processes can occur on the
same socket, and some semantic difference is desired.)

The changes are quite small.  These are relative to

/*        $NetBSD: un.h,v 1.22 1999/06/24 14:07:44 kleink Exp $   */
/*     $NetBSD: unpcb.h,v 1.11 1998/01/07 22:49:47 thorpej Exp $       */
/*      $NetBSD: uipc_usrreq.c,v 1.45 1999/06/17 23:17:45 thorpej Exp $ */

(those being the versions I had handy), but given the last-change dates
and the stability of the AF_LOCAL stuff, I would expect that if those
aren't the -current revs, the tweaks are relatively minor.

For your consideration.  Use, tweak, ignore, as you wish.

/~\ The ASCII				der Mouse
\ / Ribbon Campaign
 X  Against HTML	       mouse@rodents.montreal.qc.ca
/ \ Email!	     7D C8 61 52 5D E7 2D 39  4E F1 31 3E E8 B3 27 4B

--- OLD/sys/sys/un.h	Thu Jan  1 00:00:00 1970
+++ NEW/sys/sys/un.h	Thu Jan  1 00:00:00 1970
@@ -38,6 +38,8 @@
 #ifndef _SYS_UN_H_
 #define _SYS_UN_H_
 
+#include <sys/types.h>
+
 /*
  * Definitions for UNIX IPC domain.
  */
@@ -51,7 +53,8 @@
  * Socket options for UNIX IPC domain.
  */
 #if !defined(_XOPEN_SOURCE)
-#define	LOCAL_CREDS	0x0001		/* pass credentials to receiver */
+#define	LOCAL_CREDS		0x0001	/* pass credentials to receiver */
+#define	LOCAL_CREDS_STICKY	0x0002	/* LOCAL_CREDS is sticky */
 #endif
 
 #ifdef _KERNEL
--- OLD/sys/sys/unpcb.h	Thu Jan  1 00:00:00 1970
+++ NEW/sys/sys/unpcb.h	Thu Jan  1 00:00:00 1970
@@ -86,6 +86,7 @@
 
 /* unp_flags */
 #define	UNP_WANTCRED	0x0001		/* credentials wanted */
+#define	UNP_STICKYCRED	0x0002		/* UNP_WANTCRED is sticky */
 
 #define	sotounpcb(so)	((struct unpcb *)((so)->so_pcb))
 
--- OLD/sys/kern/uipc_usrreq.c	Thu Jan  1 00:00:00 1970
+++ NEW/sys/kern/uipc_usrreq.c	Thu Jan  1 00:00:00 1970
@@ -212,6 +212,16 @@
 
 	case PRU_CONNECT:
 		error = unp_connect(so, nam, p);
+		if ((error == 0) &&
+		    (so->so_type == SOCK_STREAM) &&
+		    (unp->unp_conn->unp_flags & UNP_WANTCRED)) {
+			/* Do a zero-length send to get creds sent. */
+			MGETHDR(m, M_WAIT, MT_DATA);
+			m->m_pkthdr.len = 0;
+			m->m_pkthdr.rcvif = 0;
+			m->m_len = 0;
+			error = uipc_usrreq(so, PRU_SEND, m, 0, 0, p);
+		}
 		break;
 
 	case PRU_CONNECT2:
@@ -307,9 +317,10 @@
 			if (unp->unp_conn->unp_flags & UNP_WANTCRED) {
 				/*
 				 * Credentials are passed only once on
-				 * SOCK_STREAM.
+				 * SOCK_STREAM, unless sticky.
 				 */
-				unp->unp_conn->unp_flags &= ~UNP_WANTCRED;
+				if (! (unp->unp_conn->unp_flags & UNP_STICKYCRED))
+					unp->unp_conn->unp_flags &= ~UNP_WANTCRED;
 				control = unp_addsockcred(p, control);
 			}
 			/*
@@ -411,6 +422,7 @@
 	case PRCO_SETOPT:
 		switch (optname) {
 		case LOCAL_CREDS:
+		case LOCAL_CREDS_STICKY:
 			if (m == NULL || m->m_len != sizeof(int))
 				error = EINVAL;
 			else {
@@ -425,6 +437,10 @@
 				case LOCAL_CREDS:
 					OPTSET(UNP_WANTCRED);
 					break;
+
+				case LOCAL_CREDS_STICKY:
+					OPTSET(UNP_STICKYCRED);
+					break;
 				}
 			}
 			break;
@@ -441,6 +457,7 @@
 	case PRCO_GETOPT:
 		switch (optname) {
 		case LOCAL_CREDS:
+		case LOCAL_CREDS_STICKY:
 			*mp = m = m_get(M_WAIT, MT_SOOPTS);
 			m->m_len = sizeof(int);
 			switch (optname) {
@@ -449,6 +466,10 @@
 
 			case LOCAL_CREDS:
 				optval = OPTBIT(UNP_WANTCRED);
+				break;
+
+			case LOCAL_CREDS_STICKY:
+				optval = OPTBIT(UNP_STICKYCRED);
 				break;
 			}
 			*mtod(m, int *) = optval;