Index: head/share/man/man4/unix.4 =================================================================== --- head/share/man/man4/unix.4 +++ head/share/man/man4/unix.4 @@ -28,7 +28,7 @@ .\" @(#)unix.4 8.1 (Berkeley) 6/9/93 .\" $FreeBSD$ .\" -.Dd August 3, 2020 +.Dd November 2, 2020 .Dt UNIX 4 .Os .Sh NAME @@ -201,7 +201,7 @@ .Xr setsockopt 2 and tested with .Xr getsockopt 2 : -.Bl -tag -width ".Dv LOCAL_CONNWAIT" +.Bl -tag -width ".Dv LOCAL_CREDS_PERSISTENT" .It Dv LOCAL_CREDS This option may be enabled on .Dv SOCK_DGRAM , @@ -287,6 +287,19 @@ Therefore, a message accompanied by a particular .Fa sc_euid value should not be trusted as being from that user. +.It Dv LOCAL_CREDS_PERSISTENT +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. +The +.Dv LOCAL_CREDS +and +.Dv LOCAL_CREDS_PERSISTENT +options are mutually exclusive. .It Dv LOCAL_CONNWAIT Used with .Dv SOCK_STREAM Index: head/sys/kern/uipc_usrreq.c =================================================================== --- head/sys/kern/uipc_usrreq.c +++ head/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,12 +1094,13 @@ 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. + * Credentials are passed only once on SOCK_STREAM and + * SOCK_SEQPACKET (LOCAL_CREDS => WANTCRED_ONESHOT), or + * forever (LOCAL_CREDS_PERSISTENT => WANTCRED_ALWAYS). */ - unp2->unp_flags &= ~UNP_WANTCRED; + unp2->unp_flags &= ~UNP_WANTCRED_ONESHOT; control = unp_addsockcred(td, control); } @@ -1405,10 +1406,16 @@ case LOCAL_CREDS: /* Unlocked read. */ - optval = unp->unp_flags & UNP_WANTCRED ? 1 : 0; + optval = unp->unp_flags & UNP_WANTCRED_ONESHOT ? 1 : 0; error = sooptcopyout(sopt, &optval, sizeof(optval)); break; + case LOCAL_CREDS_PERSISTENT: + /* 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,28 +1431,38 @@ case SOPT_SET: switch (sopt->sopt_name) { case LOCAL_CREDS: + case LOCAL_CREDS_PERSISTENT: case LOCAL_CONNWAIT: error = sooptcopyin(sopt, &optval, sizeof(optval), sizeof(optval)); if (error) break; -#define OPTSET(bit) do { \ +#define OPTSET(bit, exclusive) do { \ UNP_PCB_LOCK(unp); \ - if (optval) \ - unp->unp_flags |= bit; \ - else \ - unp->unp_flags &= ~bit; \ + if (optval) { \ + if ((unp->unp_flags & (exclusive)) != 0) { \ + UNP_PCB_UNLOCK(unp); \ + error = EINVAL; \ + break; \ + } \ + unp->unp_flags |= (bit); \ + } else \ + unp->unp_flags &= ~(bit); \ UNP_PCB_UNLOCK(unp); \ } while (0) switch (sopt->sopt_name) { case LOCAL_CREDS: - OPTSET(UNP_WANTCRED); + OPTSET(UNP_WANTCRED_ONESHOT, UNP_WANTCRED_ALWAYS); break; + case LOCAL_CREDS_PERSISTENT: + OPTSET(UNP_WANTCRED_ALWAYS, UNP_WANTCRED_ONESHOT); + break; + case LOCAL_CONNWAIT: - OPTSET(UNP_CONNWAIT); + OPTSET(UNP_CONNWAIT, 0); break; default: @@ -1651,8 +1668,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,8 +2869,12 @@ db_printf("%sUNP_HAVEPC", comma ? ", " : ""); comma = 1; } - if (unp_flags & UNP_WANTCRED) { - db_printf("%sUNP_WANTCRED", comma ? ", " : ""); + if (unp_flags & UNP_WANTCRED_ALWAYS) { + db_printf("%sUNP_WANTCRED_ALWAYS", comma ? ", " : ""); + comma = 1; + } + if (unp_flags & UNP_WANTCRED_ONESHOT) { + db_printf("%sUNP_WANTCRED_ONESHOT", comma ? ", " : ""); comma = 1; } if (unp_flags & UNP_CONNWAIT) { Index: head/sys/sys/un.h =================================================================== --- head/sys/sys/un.h +++ head/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_CREDS_PERSISTENT 3 /* pass credentials to receiver */ #define LOCAL_CONNWAIT 4 /* connects block until accepted */ /* Start of reserved space for third-party socket options. */ Index: head/sys/sys/unpcb.h =================================================================== --- head/sys/sys/unpcb.h +++ head/sys/sys/unpcb.h @@ -107,9 +107,12 @@ * 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_ONESHOT 0x004 /* credentials wanted once */ #define UNP_CONNWAIT 0x008 /* connect blocks until accepted */ + +#define UNP_WANTCRED_MASK (UNP_WANTCRED_ONESHOT | UNP_WANTCRED_ALWAYS) /* * These flags are used to handle non-atomicity in connect() and bind()