mirror of
git://sourceware.org/git/newlib-cygwin.git
synced 2025-02-13 04:29:09 +08:00
172 lines
5.8 KiB
C
172 lines
5.8 KiB
C
/*************************************************************************\
|
|
* 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_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"
|
|
|
|
int
|
|
main(int argc, char *argv[])
|
|
{
|
|
int data, sfd, opt;
|
|
ssize_t ns;
|
|
Boolean useDatagramSocket, noExplicitCreds;
|
|
struct msghdr msgh;
|
|
struct iovec iov;
|
|
|
|
/* 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 */
|
|
|
|
/* Parse command-line options */
|
|
|
|
useDatagramSocket = FALSE;
|
|
noExplicitCreds = FALSE;
|
|
|
|
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. */
|
|
|
|
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 */
|
|
|
|
msgh.msg_iov = &iov;
|
|
msgh.msg_iovlen = 1;
|
|
iov.iov_base = &data;
|
|
iov.iov_len = sizeof(int);
|
|
|
|
/* Data is optionally taken from command line */
|
|
|
|
data = (argc > optind) ? atoi(argv[optind]) : 12345;
|
|
fprintf(stderr, "Sending data = %d\n", 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 {
|
|
struct ucred *ucredp;
|
|
|
|
/* 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 */
|
|
|
|
cmsgp = CMSG_FIRSTHDR(&msgh);
|
|
cmsgp->cmsg_len = CMSG_LEN(sizeof(struct ucred));
|
|
cmsgp->cmsg_level = SOL_SOCKET;
|
|
cmsgp->cmsg_type = SCM_CREDENTIALS;
|
|
|
|
/* Set 'ucredp' to point to the data area in the 'cmsghdr' */
|
|
|
|
ucredp = (struct ucred *) CMSG_DATA(cmsgp);
|
|
|
|
/* Use sender's own PID, real UID, and real GID, unless
|
|
alternate values were supplied on the command line */
|
|
|
|
ucredp->pid = getpid();
|
|
if (argc > optind + 1 && strcmp(argv[optind + 1], "-") != 0)
|
|
ucredp->pid = atoi(argv[optind + 1]);
|
|
|
|
ucredp->uid = getuid();
|
|
if (argc > optind + 2 && strcmp(argv[optind + 2], "-") != 0)
|
|
ucredp->uid = atoi(argv[optind + 2]);
|
|
|
|
ucredp->gid = getgid();
|
|
if (argc > optind + 3 && strcmp(argv[optind + 3], "-") != 0)
|
|
ucredp->gid = atoi(argv[optind + 3]);
|
|
|
|
printf("Send credentials pid=%ld, uid=%ld, gid=%ld\n",
|
|
(long) ucredp->pid, (long) ucredp->uid, (long) ucredp->gid);
|
|
}
|
|
|
|
/* Connect to the peer socket */
|
|
|
|
sfd = unixConnect(SOCK_PATH, useDatagramSocket ? SOCK_DGRAM : SOCK_STREAM);
|
|
if (sfd == -1)
|
|
errExit("unixConnect");
|
|
|
|
/* Send real plus ancillary data */
|
|
|
|
ns = sendmsg(sfd, &msgh, 0);
|
|
if (ns == -1)
|
|
errExit("sendmsg");
|
|
|
|
printf("sendmsg() returned %ld\n", (long) ns);
|
|
|
|
exit(EXIT_SUCCESS);
|
|
}
|