1 /* $OpenBSD: privsep_fdpass.c,v 1.8 2012/04/04 17:24:50 deraadt Exp $ */ 2 3 /* 4 * Copyright (c) 2002 Matthieu Herrb 5 * Copyright (c) 2001 Niels Provos <provos@citi.umich.edu> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER 16 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING 17 * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/types.h> 21 #include <sys/socket.h> 22 #include <sys/uio.h> 23 24 #include <err.h> 25 #include <errno.h> 26 #include <fcntl.h> 27 #include <string.h> 28 #include <unistd.h> 29 30 #include "privsep.h" 31 32 void 33 send_fd(int sock, int fd) 34 { 35 struct msghdr msg; 36 union { 37 struct cmsghdr hdr; 38 char buf[CMSG_SPACE(sizeof(int))]; 39 } cmsgbuf; 40 struct cmsghdr *cmsg; 41 struct iovec vec; 42 int result = 0; 43 ssize_t n; 44 45 memset(&msg, 0, sizeof(msg)); 46 47 if (fd >= 0) { 48 msg.msg_control = (caddr_t)&cmsgbuf.buf; 49 msg.msg_controllen = sizeof(cmsgbuf.buf); 50 cmsg = CMSG_FIRSTHDR(&msg); 51 cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 52 cmsg->cmsg_level = SOL_SOCKET; 53 cmsg->cmsg_type = SCM_RIGHTS; 54 *(int *)CMSG_DATA(cmsg) = fd; 55 } else 56 result = errno; 57 58 vec.iov_base = &result; 59 vec.iov_len = sizeof(int); 60 msg.msg_iov = &vec; 61 msg.msg_iovlen = 1; 62 63 if ((n = sendmsg(sock, &msg, 0)) == -1) 64 warn("%s: sendmsg(%d)", __func__, sock); 65 if (n != sizeof(int)) 66 warnx("%s: sendmsg: expected sent 1 got %ld", 67 __func__, (long)n); 68 } 69 70 int 71 receive_fd(int sock) 72 { 73 struct msghdr msg; 74 union { 75 struct cmsghdr hdr; 76 char buf[CMSG_SPACE(sizeof(int))]; 77 } cmsgbuf; 78 struct cmsghdr *cmsg; 79 struct iovec vec; 80 ssize_t n; 81 int result; 82 int fd; 83 84 memset(&msg, 0, sizeof(msg)); 85 vec.iov_base = &result; 86 vec.iov_len = sizeof(int); 87 msg.msg_iov = &vec; 88 msg.msg_iovlen = 1; 89 msg.msg_control = &cmsgbuf.buf; 90 msg.msg_controllen = sizeof(cmsgbuf.buf); 91 92 if ((n = recvmsg(sock, &msg, 0)) == -1) { 93 warn("%s: recvmsg", __func__); 94 return -1; 95 } 96 if (n != sizeof(int)) 97 warnx("%s: recvmsg: expected received 1 got %ld", 98 __func__, (long)n); 99 if (result == 0) { 100 cmsg = CMSG_FIRSTHDR(&msg); 101 if (cmsg == NULL) { 102 warnx("%s: no message header", __func__); 103 return (-1); 104 } 105 if (cmsg->cmsg_type != SCM_RIGHTS) 106 warnx("%s: expected type %d got %d", __func__, 107 SCM_RIGHTS, cmsg->cmsg_type); 108 fd = (*(int *)CMSG_DATA(cmsg)); 109 return (fd); 110 } else { 111 errno = result; 112 return (-1); 113 } 114 } 115