#include "sendfd.h" #include "sys/socket.h" /* cmsghdr */ #include "stdio.h" /* perror */ ssize_t send_fd(int dst_fd, int fd, const struct iovec *iov) { struct msghdr msg = { 0 }; /* openssh expects to receive a dummy length=1 iovec? */ char ch = 0; struct iovec vecDefault = { 0 }; vecDefault.iov_base = &ch; vecDefault.iov_len = 1; msg.msg_iov = iov == NULL ? &vecDefault : iov; msg.msg_iovlen = 1; union { struct cmsghdr align; char buf[CMSG_SPACE(sizeof(int))]; } u; msg.msg_control = u.buf; msg.msg_controllen = sizeof(u.buf); struct cmsghdr *cmptr; cmptr = CMSG_FIRSTHDR(&msg); if (cmptr == NULL) { perror("ch-proxy/send_fd/CMSG_FIRSTHDR: failed to initialize msg_control\n"); } cmptr->cmsg_len = CMSG_LEN(sizeof(int)); cmptr->cmsg_level = SOL_SOCKET; cmptr->cmsg_type = SCM_RIGHTS; *((int*) CMSG_DATA(cmptr)) = fd; return (sendmsg(dst_fd, &msg, 0)); } int recv_fd(int sock, int flags) { int out = -1; struct msghdr msg = { 0 }; struct cmsghdr *cmsg = NULL; struct iovec iov = { 0 }; char dummy = 0; msg.msg_iov = &iov; msg.msg_iovlen = 1; iov.iov_base = &dummy; iov.iov_len = sizeof(dummy); union { struct cmsghdr align; char buf[CMSG_SPACE(sizeof(int))]; } u; msg.msg_control = u.buf; msg.msg_controllen = sizeof(u.buf); int bytes = 0; if ((bytes = recvmsg(sock, &msg, flags)) < 0) { perror("recv_fd: recvmsg"); return -1; } for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg)) { if (cmsg->cmsg_level != SOL_SOCKET) { continue; } if (cmsg->cmsg_type != SCM_RIGHTS) { continue; } if (CMSG_LEN(cmsg) < sizeof(out)) { continue; } out = *(int*)CMSG_DATA(cmsg); } return out; }