Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'winsup/cygwin/socket_tests/scm_cred_recv.c')
-rw-r--r--winsup/cygwin/socket_tests/scm_cred_recv.c173
1 files changed, 173 insertions, 0 deletions
diff --git a/winsup/cygwin/socket_tests/scm_cred_recv.c b/winsup/cygwin/socket_tests/scm_cred_recv.c
new file mode 100644
index 000000000..121b472a4
--- /dev/null
+++ b/winsup/cygwin/socket_tests/scm_cred_recv.c
@@ -0,0 +1,173 @@
+/*************************************************************************\
+* Copyright (C) Michael Kerrisk, 2018. *
+* *
+* 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"
+
+int
+main(int argc, char *argv[])
+{
+ int data, lfd, sfd, optval, opt;
+ ssize_t nr;
+ Boolean useDatagramSocket;
+ struct msghdr msgh;
+ struct iovec iov;
+ struct ucred *ucredp, ucred;
+
+ /* 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;
+ struct cmsghdr *cmsgp; /* Pointer used to iterate through
+ headers in ancillary data */
+ socklen_t len;
+
+ /* Parse command-line options */
+
+ useDatagramSocket = FALSE;
+
+ 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);
+
+ if (useDatagramSocket) {
+ sfd = unixBind(SOCK_PATH, SOCK_DGRAM);
+ if (sfd == -1)
+ errExit("unixBind");
+
+ } else {
+ 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 */
+
+ optval = 1;
+ if (setsockopt(sfd, SOL_SOCKET, SO_PASSCRED, &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. */
+
+ msgh.msg_name = NULL;
+ msgh.msg_namelen = 0;
+
+ /* Set fields of 'msgh' to point to buffer used to receive (real)
+ data read by recvmsg() */
+
+ msgh.msg_iov = &iov;
+ msgh.msg_iovlen = 1;
+ iov.iov_base = &data;
+ iov.iov_len = sizeof(int);
+
+ /* 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 */
+
+ nr = recvmsg(sfd, &msgh, 0);
+ if (nr == -1)
+ errExit("recvmsg");
+ printf("recvmsg() returned %ld\n", (long) nr);
+
+ if (nr > 0)
+ printf("Received data = %d\n", data);
+
+ /* Get the address of the first 'cmsghdr' in the received
+ ancillary data */
+
+ 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");
+
+ /* The data area of the 'cmsghdr' is a 'struct ucred', so assign
+ the address of the data area to a suitable pointer */
+
+ ucredp = (struct ucred *) CMSG_DATA(cmsgp);
+
+ /* Display the credentials from the received data area */
+
+ printf("Received credentials pid=%ld, uid=%ld, gid=%ld\n",
+ (long) ucredp->pid, (long) ucredp->uid, (long) ucredp->gid);
+
+ /* The Linux-specific, read-only SO_PEERCRED socket option returns
+ credential information about the peer, as described in socket(7).
+ This operation can be performed on UNIX domain stream sockets and on
+ UNIX domain sockets (stream or datagram) created with socketpair(). */
+
+ len = sizeof(struct ucred);
+ if (getsockopt(sfd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) == -1)
+ errExit("getsockopt");
+
+ printf("Credentials from SO_PEERCRED: pid=%ld, euid=%ld, egid=%ld\n",
+ (long) ucred.pid, (long) ucred.uid, (long) ucred.gid);
+
+ exit(EXIT_SUCCESS);
+}