Last active
February 27, 2023 08:28
-
-
Save mihalicyn/268e51d2ecf32093763df62ece045af8 to your computer and use it in GitHub Desktop.
SCM_PIDFD example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* This code is based on Michael Kerrisk examples from: | |
* https://man7.org/tlpi/code/online/dist/sockets/scm_cred_recv.c.html | |
* | |
* That's a proposal API for a new SCM_PIDFD auxiliary socket message | |
* | |
* Reference https://github.com/uapi-group/kernel-features | |
*/ | |
/*************************************************************************\ | |
* Copyright (C) Michael Kerrisk, 2022. * | |
* * | |
* This program is free software. You may use, modify, and redistribute it * | |
* under the terms of the GNU General Public License as published by the * | |
* Free Software Foundation, either version 3 or (at your option) any * | |
* later version. This program is distributed without any warranty. See * | |
* the file COPYING.gpl-v3 for details. * | |
\*************************************************************************/ | |
/* Supplementary program for Chapter 61 */ | |
/* scm_cred_recv.c | |
Used in conjunction with scm_cred_send.c to demonstrate passing of | |
process credentials via a UNIX domain socket. | |
This program receives credentials sent to a UNIX domain socket. | |
Usage is as shown in the usageErr() call below. | |
Credentials can be exchanged over stream or datagram sockets. This program | |
uses stream sockets by default; the "-d" command-line option specifies | |
that datagram sockets should be used instead. | |
This program is Linux-specific. | |
See also scm_multi_recv.c. | |
*/ | |
#include "scm_cred.h" | |
#define SO_PASSPIDFD 76 | |
#define SCM_PIDFD 0x04 /* rw: pidfd (int) */ | |
int | |
main(int argc, char *argv[]) | |
{ | |
/* Allocate a char array of suitable size to hold the ancillary data. | |
However, since this buffer is in reality a 'struct cmsghdr', use a | |
union to ensure that it is aligned as required for that structure. | |
Alternatively, we could allocate the buffer using malloc(), which | |
returns a buffer that satisfies the strictest alignment | |
requirements of any type */ | |
union { | |
char buf[CMSG_SPACE(sizeof(struct ucred))+CMSG_SPACE(sizeof(int))]; | |
/* Space large enough to hold a 'ucred' structure and pidfd */ | |
struct cmsghdr align; | |
} controlMsg; | |
/* Parse command-line options */ | |
bool useDatagramSocket = false; | |
int opt; | |
while ((opt = getopt(argc, argv, "d")) != -1) { | |
switch (opt) { | |
case 'd': | |
useDatagramSocket = true; | |
break; | |
default: | |
usageErr("%s [-d]\n" | |
" -d use datagram socket\n", argv[0]); | |
} | |
} | |
/* Create socket bound to a well-known address. In the case where | |
we are using stream sockets, also make the socket a listening | |
socket and accept a connection on the socket. */ | |
if (remove(SOCK_PATH) == -1 && errno != ENOENT) | |
errExit("remove-%s", SOCK_PATH); | |
int sfd; | |
if (useDatagramSocket) { | |
sfd = unixBind(SOCK_PATH, SOCK_DGRAM); | |
if (sfd == -1) | |
errExit("unixBind"); | |
} else { | |
int lfd = unixBind(SOCK_PATH, SOCK_STREAM); | |
if (lfd == -1) | |
errExit("unixBind"); | |
if (listen(lfd, 5) == -1) | |
errExit("listen"); | |
sfd = accept(lfd, NULL, NULL); | |
if (sfd == -1) | |
errExit("accept"); | |
} | |
/* We must set the SO_PASSCRED socket option in order to receive | |
credentials */ | |
int optval = 1; | |
if (setsockopt(sfd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) | |
errExit("setsockopt"); | |
/* We must set the SO_PASSPIDFD socket option in order to receive | |
pidfd */ | |
optval = 1; | |
if (setsockopt(sfd, SOL_SOCKET, SO_PASSPIDFD, &optval, sizeof(optval)) == -1) | |
errExit("setsockopt"); | |
/* The 'msg_name' field can be set to point to a buffer where the | |
kernel will place the address of the peer socket. However, we don't | |
need the address of the peer, so we set this field to NULL. */ | |
struct msghdr msgh; | |
msgh.msg_name = NULL; | |
msgh.msg_namelen = 0; | |
/* Set fields of 'msgh' to point to buffer used to receive (real) | |
data read by recvmsg() */ | |
struct iovec iov; | |
int data; | |
msgh.msg_iov = &iov; | |
msgh.msg_iovlen = 1; | |
iov.iov_base = &data; | |
iov.iov_len = sizeof(data); | |
/* Set 'msgh' fields to describe the ancillary data buffer */ | |
msgh.msg_control = controlMsg.buf; | |
msgh.msg_controllen = sizeof(controlMsg.buf); | |
/* Receive real plus ancillary data */ | |
ssize_t nr = recvmsg(sfd, &msgh, 0); | |
if (nr == -1) | |
errExit("recvmsg"); | |
printf("recvmsg() returned %zd\n", nr); | |
if (nr > 0) | |
printf("Received data = %d\n", data); | |
/* Get the address of the first 'cmsghdr' in the received | |
ancillary data */ | |
struct cmsghdr *cmsgp = CMSG_FIRSTHDR(&msgh); | |
/* Check the validity of the 'cmsghdr' */ | |
if (cmsgp == NULL || cmsgp->cmsg_len != CMSG_LEN(sizeof(struct ucred))) | |
fatal("bad cmsg header / message length"); | |
if (cmsgp->cmsg_level != SOL_SOCKET) | |
fatal("cmsg_level != SOL_SOCKET"); | |
if (cmsgp->cmsg_type != SCM_CREDENTIALS) | |
fatal("cmsg_type != SCM_CREDENTIALS"); | |
/* Copy the contents of the data field of the 'cmsghdr' to a | |
'struct ucred'. */ | |
struct ucred rcred; | |
memcpy(&rcred, CMSG_DATA(cmsgp), sizeof(struct ucred)); | |
/* Display the credentials from the received data area */ | |
printf("Received credentials pid=%ld, uid=%ld, gid=%ld\n", | |
(long) rcred.pid, (long) rcred.uid, (long) rcred.gid); | |
cmsgp = CMSG_NXTHDR(&msgh, cmsgp); | |
if (cmsgp == NULL || cmsgp->cmsg_len != CMSG_LEN(sizeof(int))) | |
fatal("bad cmsg header / message length"); | |
if (cmsgp->cmsg_level != SOL_SOCKET) | |
fatal("cmsg_level != SOL_SOCKET"); | |
if (cmsgp->cmsg_type != SCM_PIDFD) | |
fatal("cmsg_type != SCM_PIDFD"); | |
int pidfd; | |
memcpy(&pidfd, CMSG_DATA(cmsgp), sizeof(int)); | |
printf("Received pidfd=%d\n", | |
pidfd); | |
char buf[100]; | |
sprintf(buf, "cat /proc/%d/fdinfo/%d", getpid(), pidfd); | |
system(buf); | |
exit(EXIT_SUCCESS); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From fbc6eb4f12d87dd3e3e36af3fd49ca1f30a7d04e Mon Sep 17 00:00:00 2001 | |
From: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com> | |
Date: Sun, 26 Feb 2023 23:04:18 +0100 | |
Subject: [PATCH] scm: add SO_PASSPIDFD and SCM_PIDFD | |
Signed-off-by: Alexander Mikhalitsyn <aleksandr.mikhalitsyn@canonical.com> | |
--- | |
arch/alpha/include/uapi/asm/socket.h | 2 ++ | |
arch/mips/include/uapi/asm/socket.h | 2 ++ | |
arch/parisc/include/uapi/asm/socket.h | 2 ++ | |
arch/sparc/include/uapi/asm/socket.h | 2 ++ | |
include/linux/net.h | 1 + | |
include/linux/socket.h | 1 + | |
include/net/scm.h | 16 +++++++++++++++- | |
include/uapi/asm-generic/socket.h | 2 ++ | |
net/core/sock.c | 11 +++++++++++ | |
net/mptcp/sockopt.c | 1 + | |
net/unix/af_unix.c | 18 +++++++++++++----- | |
tools/include/uapi/asm-generic/socket.h | 2 ++ | |
12 files changed, 54 insertions(+), 6 deletions(-) | |
diff --git a/arch/alpha/include/uapi/asm/socket.h b/arch/alpha/include/uapi/asm/socket.h | |
index 739891b94136..ff310613ae64 100644 | |
--- a/arch/alpha/include/uapi/asm/socket.h | |
+++ b/arch/alpha/include/uapi/asm/socket.h | |
@@ -137,6 +137,8 @@ | |
#define SO_RCVMARK 75 | |
+#define SO_PASSPIDFD 76 | |
+ | |
#if !defined(__KERNEL__) | |
#if __BITS_PER_LONG == 64 | |
diff --git a/arch/mips/include/uapi/asm/socket.h b/arch/mips/include/uapi/asm/socket.h | |
index 18f3d95ecfec..762dcb80e4ec 100644 | |
--- a/arch/mips/include/uapi/asm/socket.h | |
+++ b/arch/mips/include/uapi/asm/socket.h | |
@@ -148,6 +148,8 @@ | |
#define SO_RCVMARK 75 | |
+#define SO_PASSPIDFD 76 | |
+ | |
#if !defined(__KERNEL__) | |
#if __BITS_PER_LONG == 64 | |
diff --git a/arch/parisc/include/uapi/asm/socket.h b/arch/parisc/include/uapi/asm/socket.h | |
index f486d3dfb6bb..df16a3e16d64 100644 | |
--- a/arch/parisc/include/uapi/asm/socket.h | |
+++ b/arch/parisc/include/uapi/asm/socket.h | |
@@ -129,6 +129,8 @@ | |
#define SO_RCVMARK 0x4049 | |
+#define SO_PASSPIDFD 0x404A | |
+ | |
#if !defined(__KERNEL__) | |
#if __BITS_PER_LONG == 64 | |
diff --git a/arch/sparc/include/uapi/asm/socket.h b/arch/sparc/include/uapi/asm/socket.h | |
index 2fda57a3ea86..6e2847804fea 100644 | |
--- a/arch/sparc/include/uapi/asm/socket.h | |
+++ b/arch/sparc/include/uapi/asm/socket.h | |
@@ -130,6 +130,8 @@ | |
#define SO_RCVMARK 0x0054 | |
+#define SO_PASSPIDFD 0x0055 | |
+ | |
#if !defined(__KERNEL__) | |
diff --git a/include/linux/net.h b/include/linux/net.h | |
index b73ad8e3c212..c234dfbe7a30 100644 | |
--- a/include/linux/net.h | |
+++ b/include/linux/net.h | |
@@ -43,6 +43,7 @@ struct net; | |
#define SOCK_PASSSEC 4 | |
#define SOCK_SUPPORT_ZC 5 | |
#define SOCK_CUSTOM_SOCKOPT 6 | |
+#define SOCK_PASSPIDFD 7 | |
#ifndef ARCH_HAS_SOCKET_TYPES | |
/** | |
diff --git a/include/linux/socket.h b/include/linux/socket.h | |
index 13c3a237b9c9..1aa0130b812b 100644 | |
--- a/include/linux/socket.h | |
+++ b/include/linux/socket.h | |
@@ -177,6 +177,7 @@ static inline size_t msg_data_left(struct msghdr *msg) | |
#define SCM_RIGHTS 0x01 /* rw: access rights (array of int) */ | |
#define SCM_CREDENTIALS 0x02 /* rw: struct ucred */ | |
#define SCM_SECURITY 0x03 /* rw: security label */ | |
+#define SCM_PIDFD 0x04 /* rw: pidfd (int) */ | |
struct ucred { | |
__u32 pid; | |
diff --git a/include/net/scm.h b/include/net/scm.h | |
index 585adc1346bd..4617fbc65294 100644 | |
--- a/include/net/scm.h | |
+++ b/include/net/scm.h | |
@@ -124,7 +124,9 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg, | |
struct scm_cookie *scm, int flags) | |
{ | |
if (!msg->msg_control) { | |
- if (test_bit(SOCK_PASSCRED, &sock->flags) || scm->fp || | |
+ if (test_bit(SOCK_PASSCRED, &sock->flags) || | |
+ test_bit(SOCK_PASSPIDFD, &sock->flags) || | |
+ scm->fp || | |
scm_has_secdata(sock)) | |
msg->msg_flags |= MSG_CTRUNC; | |
scm_destroy(scm); | |
@@ -141,6 +143,18 @@ static __inline__ void scm_recv(struct socket *sock, struct msghdr *msg, | |
put_cmsg(msg, SOL_SOCKET, SCM_CREDENTIALS, sizeof(ucreds), &ucreds); | |
} | |
+ if (test_bit(SOCK_PASSPIDFD, &sock->flags)) { | |
+ int pidfd; | |
+ | |
+ if (WARN_ON_ONCE(!scm->pid) || | |
+ !pid_has_task(scm->pid, PIDTYPE_TGID)) | |
+ pidfd = -ESRCH; | |
+ else | |
+ pidfd = pidfd_create(scm->pid, 0); | |
+ | |
+ put_cmsg(msg, SOL_SOCKET, SCM_PIDFD, sizeof(int), &pidfd); | |
+ } | |
+ | |
scm_destroy_cred(scm); | |
scm_passec(sock, msg, scm); | |
diff --git a/include/uapi/asm-generic/socket.h b/include/uapi/asm-generic/socket.h | |
index 638230899e98..b76169fdb80b 100644 | |
--- a/include/uapi/asm-generic/socket.h | |
+++ b/include/uapi/asm-generic/socket.h | |
@@ -132,6 +132,8 @@ | |
#define SO_RCVMARK 75 | |
+#define SO_PASSPIDFD 76 | |
+ | |
#if !defined(__KERNEL__) | |
#if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__)) | |
diff --git a/net/core/sock.c b/net/core/sock.c | |
index 341c565dbc26..255d29dec4d6 100644 | |
--- a/net/core/sock.c | |
+++ b/net/core/sock.c | |
@@ -1246,6 +1246,13 @@ int sk_setsockopt(struct sock *sk, int level, int optname, | |
clear_bit(SOCK_PASSCRED, &sock->flags); | |
break; | |
+ case SO_PASSPIDFD: | |
+ if (valbool) | |
+ set_bit(SOCK_PASSPIDFD, &sock->flags); | |
+ else | |
+ clear_bit(SOCK_PASSPIDFD, &sock->flags); | |
+ break; | |
+ | |
case SO_TIMESTAMP_OLD: | |
case SO_TIMESTAMP_NEW: | |
case SO_TIMESTAMPNS_OLD: | |
@@ -1737,6 +1744,10 @@ int sk_getsockopt(struct sock *sk, int level, int optname, | |
v.val = !!test_bit(SOCK_PASSCRED, &sock->flags); | |
break; | |
+ case SO_PASSPIDFD: | |
+ v.val = !!test_bit(SOCK_PASSPIDFD, &sock->flags); | |
+ break; | |
+ | |
case SO_PEERCRED: | |
{ | |
struct ucred peercred; | |
diff --git a/net/mptcp/sockopt.c b/net/mptcp/sockopt.c | |
index 8a9656248b0f..bd80e707d0b3 100644 | |
--- a/net/mptcp/sockopt.c | |
+++ b/net/mptcp/sockopt.c | |
@@ -355,6 +355,7 @@ static int mptcp_setsockopt_sol_socket(struct mptcp_sock *msk, int optname, | |
case SO_BROADCAST: | |
case SO_BSDCOMPAT: | |
case SO_PASSCRED: | |
+ case SO_PASSPIDFD: | |
case SO_PASSSEC: | |
case SO_RXQ_OVFL: | |
case SO_WIFI_STATUS: | |
diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c | |
index 347122c3575e..45ab9264c0ba 100644 | |
--- a/net/unix/af_unix.c | |
+++ b/net/unix/af_unix.c | |
@@ -1361,7 +1361,8 @@ static int unix_dgram_connect(struct socket *sock, struct sockaddr *addr, | |
if (err) | |
goto out; | |
- if (test_bit(SOCK_PASSCRED, &sock->flags) && | |
+ if ((test_bit(SOCK_PASSCRED, &sock->flags) || | |
+ test_bit(SOCK_PASSPIDFD, &sock->flags)) && | |
!unix_sk(sk)->addr) { | |
err = unix_autobind(sk); | |
if (err) | |
@@ -1469,7 +1470,8 @@ static int unix_stream_connect(struct socket *sock, struct sockaddr *uaddr, | |
if (err) | |
goto out; | |
- if (test_bit(SOCK_PASSCRED, &sock->flags) && !u->addr) { | |
+ if ((test_bit(SOCK_PASSCRED, &sock->flags) || | |
+ test_bit(SOCK_PASSPIDFD, &sock->flags)) && !u->addr) { | |
err = unix_autobind(sk); | |
if (err) | |
goto out; | |
@@ -1670,6 +1672,8 @@ static void unix_sock_inherit_flags(const struct socket *old, | |
{ | |
if (test_bit(SOCK_PASSCRED, &old->flags)) | |
set_bit(SOCK_PASSCRED, &new->flags); | |
+ if (test_bit(SOCK_PASSPIDFD, &old->flags)) | |
+ set_bit(SOCK_PASSPIDFD, &new->flags); | |
if (test_bit(SOCK_PASSSEC, &old->flags)) | |
set_bit(SOCK_PASSSEC, &new->flags); | |
} | |
@@ -1819,8 +1823,10 @@ static bool unix_passcred_enabled(const struct socket *sock, | |
const struct sock *other) | |
{ | |
return test_bit(SOCK_PASSCRED, &sock->flags) || | |
+ test_bit(SOCK_PASSPIDFD, &sock->flags) || | |
!other->sk_socket || | |
- test_bit(SOCK_PASSCRED, &other->sk_socket->flags); | |
+ test_bit(SOCK_PASSCRED, &other->sk_socket->flags) || | |
+ test_bit(SOCK_PASSPIDFD, &other->sk_socket->flags); | |
} | |
/* | |
@@ -1922,7 +1928,8 @@ static int unix_dgram_sendmsg(struct socket *sock, struct msghdr *msg, | |
goto out; | |
} | |
- if (test_bit(SOCK_PASSCRED, &sock->flags) && !u->addr) { | |
+ if ((test_bit(SOCK_PASSCRED, &sock->flags) || | |
+ test_bit(SOCK_PASSPIDFD, &sock->flags)) && !u->addr) { | |
err = unix_autobind(sk); | |
if (err) | |
goto out; | |
@@ -2818,7 +2825,8 @@ static int unix_stream_read_generic(struct unix_stream_read_state *state, | |
/* Never glue messages from different writers */ | |
if (!unix_skb_scm_eq(skb, &scm)) | |
break; | |
- } else if (test_bit(SOCK_PASSCRED, &sock->flags)) { | |
+ } else if (test_bit(SOCK_PASSCRED, &sock->flags) || | |
+ test_bit(SOCK_PASSPIDFD, &sock->flags)) { | |
/* Copy credentials */ | |
scm_set_cred(&scm, UNIXCB(skb).pid, UNIXCB(skb).uid, UNIXCB(skb).gid); | |
unix_set_secdata(&scm, skb); | |
diff --git a/tools/include/uapi/asm-generic/socket.h b/tools/include/uapi/asm-generic/socket.h | |
index 8756df13be50..fbbc4bf53ee3 100644 | |
--- a/tools/include/uapi/asm-generic/socket.h | |
+++ b/tools/include/uapi/asm-generic/socket.h | |
@@ -121,6 +121,8 @@ | |
#define SO_RCVMARK 75 | |
+#define SO_PASSPIDFD 76 | |
+ | |
#if !defined(__KERNEL__) | |
#if __BITS_PER_LONG == 64 || (defined(__x86_64__) && defined(__ILP32__)) | |
-- | |
2.34.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* This code is based on Michael Kerrisk examples from: | |
* https://man7.org/tlpi/code/online/dist/sockets/scm_cred_recv.c.html | |
* | |
* That's a proposal API for a new SCM_PIDFD auxiliary socket message | |
* | |
* Reference https://github.com/uapi-group/kernel-features | |
*/ | |
/*************************************************************************\ | |
* Copyright (C) Michael Kerrisk, 2022. * | |
* * | |
* This program is free software. You may use, modify, and redistribute it * | |
* under the terms of the GNU General Public License as published by the * | |
* Free Software Foundation, either version 3 or (at your option) any * | |
* later version. This program is distributed without any warranty. See * | |
* the file COPYING.gpl-v3 for details. * | |
\*************************************************************************/ | |
/* Supplementary program for Chapter 61 */ | |
/* scm_cred_send.c | |
Used in conjunction with scm_cred_recv.c to demonstrate passing of | |
process credentials via a UNIX domain socket. | |
This program sends credentials to a UNIX domain socket. | |
Usage is as shown in the usageErr() call below. | |
Credentials can be exchanged over stream or datagram sockets. This program | |
uses stream sockets by default; the "-d" command-line option specifies | |
that datagram sockets should be used instead. | |
This program is Linux-specific. | |
See also scm_multi_send.c. | |
*/ | |
#include "scm_cred.h" | |
#define SO_PASSPIDFD 76 | |
#define SCM_PIDFD 0x04 /* rw: pidfd (int) */ | |
int | |
main(int argc, char *argv[]) | |
{ | |
/* Allocate a char array of suitable size to hold the ancillary data. | |
However, since this buffer is in reality a 'struct cmsghdr', use a | |
union to ensure that it is aligned as required for that structure. | |
Alternatively, we could allocate the buffer using malloc(), which | |
returns a buffer that satisfies the strictest alignment | |
requirements of any type */ | |
union { | |
char buf[CMSG_SPACE(sizeof(struct ucred))]; | |
/* Space large enough to hold a ucred structure */ | |
struct cmsghdr align; | |
} controlMsg; | |
/* Parse command-line options */ | |
bool useDatagramSocket = false; | |
bool noExplicitCreds = false; | |
int opt; | |
while ((opt = getopt(argc, argv, "dn")) != -1) { | |
switch (opt) { | |
case 'd': | |
useDatagramSocket = true; | |
break; | |
case 'n': | |
noExplicitCreds = true; | |
break; | |
default: | |
usageErr("%s [-d] [-n] [data [PID [UID [GID]]]]\n" | |
" -d use datagram socket\n" | |
" -n don't construct explicit " | |
"credentials structure\n", argv[0]); | |
} | |
} | |
/* The 'msg_name' field can be used to specify the address of the | |
destination socket when sending a datagram. However, we do not | |
need to use this field because we use connect() below, which sets | |
a default outgoing address for datagrams. */ | |
struct msghdr msgh; | |
msgh.msg_name = NULL; | |
msgh.msg_namelen = 0; | |
/* On Linux, we must transmit at least 1 byte of real data in | |
order to send ancillary data */ | |
int data = (argc > optind) ? atoi(argv[optind]) : 12345; | |
/* Data is optionally taken from command line */ | |
fprintf(stderr, "Sending data = %d\n", data); | |
struct iovec iov; | |
msgh.msg_iov = &iov; | |
msgh.msg_iovlen = 1; | |
iov.iov_base = &data; | |
iov.iov_len = sizeof(data); | |
if (noExplicitCreds) { | |
/* Don't construct an explicit credentials structure. (It is not | |
necessary to do so, if we just want the receiver to receive | |
our real credentials.) */ | |
printf("Not explicitly sending a credentials structure\n"); | |
msgh.msg_control = NULL; | |
msgh.msg_controllen = 0; | |
} else { | |
/* Set 'msgh' fields to describe the ancillary data buffer */ | |
msgh.msg_control = controlMsg.buf; | |
msgh.msg_controllen = sizeof(controlMsg.buf); | |
/* The control message buffer must be zero-initialized in order for the | |
CMSG_NXTHDR() macro to work correctly. Although we don't need to use | |
CMSG_NXTHDR() in this example (because there is only one block of | |
ancillary data), we show this step to demonstrate best practice */ | |
memset(controlMsg.buf, 0, sizeof(controlMsg.buf)); | |
/* Set message header to describe the ancillary data that | |
we want to send */ | |
struct cmsghdr *cmsgp = CMSG_FIRSTHDR(&msgh); | |
cmsgp->cmsg_len = CMSG_LEN(sizeof(struct ucred)); | |
cmsgp->cmsg_level = SOL_SOCKET; | |
cmsgp->cmsg_type = SCM_CREDENTIALS; | |
/* Use sender's own PID, real UID, and real GID, unless | |
alternate values were supplied on the command line */ | |
struct ucred creds; | |
creds.pid = getpid(); | |
if (argc > optind + 1 && strcmp(argv[optind + 1], "-") != 0) | |
creds.pid = atoi(argv[optind + 1]); | |
creds.uid = getuid(); | |
if (argc > optind + 2 && strcmp(argv[optind + 2], "-") != 0) | |
creds.uid = atoi(argv[optind + 2]); | |
creds.gid = getgid(); | |
if (argc > optind + 3 && strcmp(argv[optind + 3], "-") != 0) | |
creds.gid = atoi(argv[optind + 3]); | |
printf("Send credentials pid=%ld, uid=%ld, gid=%ld\n", | |
(long) creds.pid, (long) creds.uid, (long) creds.gid); | |
/* Copy 'ucred' structure into data field in the 'cmsghdr' */ | |
memcpy(CMSG_DATA(cmsgp), &creds, sizeof(struct ucred)); | |
} | |
/* Connect to the peer socket */ | |
int sfd = unixConnect(SOCK_PATH, | |
useDatagramSocket ? SOCK_DGRAM : SOCK_STREAM); | |
if (sfd == -1) | |
errExit("unixConnect"); | |
/* Send real plus ancillary data */ | |
ssize_t ns = sendmsg(sfd, &msgh, 0); | |
if (ns == -1) | |
errExit("sendmsg"); | |
printf("sendmsg() returned %zd\n", ns); | |
sleep(100); | |
exit(EXIT_SUCCESS); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment