Index: share/man/man4/unix.4 =================================================================== --- share/man/man4/unix.4 +++ share/man/man4/unix.4 @@ -28,7 +28,7 @@ .\" @(#)unix.4 8.1 (Berkeley) 6/9/93 .\" $FreeBSD$ .\" -.Dd August 3, 2020 +.Dd October 30, 2020 .Dt UNIX 4 .Os .Sh NAME @@ -287,6 +287,14 @@ Therefore, a message accompanied by a particular .Fa sc_euid value should not be trusted as being from that user. +.It Dv LOCAL_PASSCRED +This option is similar to +.Dv LOCAL_CREDS , +except that socket credentials are passed on every read from a +.Dv SOCK_STREAM +or +.Dv SOCK_SEQPACKET +socket, instead of just the first read. .It Dv LOCAL_CONNWAIT Used with .Dv SOCK_STREAM Index: sys/kern/uipc_usrreq.c =================================================================== --- sys/kern/uipc_usrreq.c +++ sys/kern/uipc_usrreq.c @@ -1040,7 +1040,7 @@ break; } - if (unp2->unp_flags & UNP_WANTCRED) + if (unp2->unp_flags & UNP_WANTCRED_MASK) control = unp_addsockcred(td, control); if (unp->unp_addr != NULL) from = (struct sockaddr *)unp->unp_addr; @@ -1094,10 +1094,11 @@ break; } SOCKBUF_LOCK(&so2->so_rcv); - if (unp2->unp_flags & UNP_WANTCRED) { + if (unp2->unp_flags & UNP_WANTCRED_MASK) { /* * Credentials are passed only once on SOCK_STREAM - * and SOCK_SEQPACKET. + * and SOCK_SEQPACKET (LOCAL_CREDS => WANTCRED), or + * forever (LOCAL_PASSCRED => WANTCRED_ALWAYS). */ unp2->unp_flags &= ~UNP_WANTCRED; control = unp_addsockcred(td, control); @@ -1409,6 +1410,12 @@ error = sooptcopyout(sopt, &optval, sizeof(optval)); break; + case LOCAL_PASSCRED: + /* Unlocked read. */ + optval = unp->unp_flags & UNP_WANTCRED_ALWAYS ? 1 : 0; + error = sooptcopyout(sopt, &optval, sizeof(optval)); + break; + case LOCAL_CONNWAIT: /* Unlocked read. */ optval = unp->unp_flags & UNP_CONNWAIT ? 1 : 0; @@ -1424,6 +1431,7 @@ case SOPT_SET: switch (sopt->sopt_name) { case LOCAL_CREDS: + case LOCAL_PASSCRED: case LOCAL_CONNWAIT: error = sooptcopyin(sopt, &optval, sizeof(optval), sizeof(optval)); @@ -1433,9 +1441,9 @@ #define OPTSET(bit) do { \ UNP_PCB_LOCK(unp); \ if (optval) \ - unp->unp_flags |= bit; \ + unp->unp_flags |= (bit); \ else \ - unp->unp_flags &= ~bit; \ + unp->unp_flags &= ~(bit); \ UNP_PCB_UNLOCK(unp); \ } while (0) @@ -1444,6 +1452,10 @@ OPTSET(UNP_WANTCRED); break; + case LOCAL_PASSCRED: + OPTSET(UNP_WANTCRED_ALWAYS); + break; + case LOCAL_CONNWAIT: OPTSET(UNP_CONNWAIT); break; @@ -1651,8 +1663,7 @@ memcpy(&server_unp->unp_peercred, &listen_unp->unp_peercred, sizeof(server_unp->unp_peercred)); server_unp->unp_flags |= UNP_HAVEPC; - if (listen_unp->unp_flags & UNP_WANTCRED) - client_unp->unp_flags |= UNP_WANTCRED; + client_unp->unp_flags |= (listen_unp->unp_flags & UNP_WANTCRED_MASK); } static int @@ -2853,6 +2864,10 @@ db_printf("%sUNP_HAVEPC", comma ? ", " : ""); comma = 1; } + if (unp_flags & UNP_WANTCRED_ALWAYS) { + db_printf("%sUNP_WANTCRED_ALWAYS", comma ? ", " : ""); + comma = 1; + } if (unp_flags & UNP_WANTCRED) { db_printf("%sUNP_WANTCRED", comma ? ", " : ""); comma = 1; Index: sys/sys/un.h =================================================================== --- sys/sys/un.h +++ sys/sys/un.h @@ -67,6 +67,7 @@ /* Socket options. */ #define LOCAL_PEERCRED 1 /* retrieve peer credentials */ #define LOCAL_CREDS 2 /* pass credentials to receiver */ +#define LOCAL_PASSCRED 3 /* pass credentials to receiver */ #define LOCAL_CONNWAIT 4 /* connects block until accepted */ /* Start of reserved space for third-party socket options. */ Index: sys/sys/unpcb.h =================================================================== --- sys/sys/unpcb.h +++ sys/sys/unpcb.h @@ -107,10 +107,13 @@ * to determine whether the contents should be sent to the user or * not. */ -#define UNP_HAVEPC 0x001 -#define UNP_WANTCRED 0x004 /* credentials wanted */ +#define UNP_HAVEPC 0x001 +#define UNP_WANTCRED_ALWAYS 0x002 /* credentials wanted always */ +#define UNP_WANTCRED 0x004 /* credentials wanted once */ #define UNP_CONNWAIT 0x008 /* connect blocks until accepted */ +#define UNP_WANTCRED_MASK (UNP_WANTCRED | UNP_WANTCRED_ALWAYS) + /* * These flags are used to handle non-atomicity in connect() and bind() * operations on a socket: in particular, to avoid races between multiple