1 /* $NetBSD: unix_send_fd.c,v 1.2 2009/06/23 11:41:07 tron Exp $ */ 2 3 /*++ 4 /* NAME 5 /* unix_send_fd 3 6 /* SUMMARY 7 /* send file descriptor 8 /* SYNOPSIS 9 /* #include <iostuff.h> 10 /* 11 /* int unix_send_fd(fd, sendfd) 12 /* int fd; 13 /* int sendfd; 14 /* DESCRIPTION 15 /* unix_send_fd() sends a file descriptor over the specified 16 /* UNIX-domain socket. 17 /* 18 /* Arguments: 19 /* .IP fd 20 /* File descriptor. 21 /* .IP sendfd 22 /* Another file descriptor. 23 /* DIAGNOSTICS 24 /* unix_send_fd() returns -1 upon failure. 25 /* LICENSE 26 /* .ad 27 /* .fi 28 /* The Secure Mailer license must be distributed with this software. 29 /* AUTHOR(S) 30 /* Wietse Venema 31 /* IBM T.J. Watson Research 32 /* P.O. Box 704 33 /* Yorktown Heights, NY 10598, USA 34 /*--*/ 35 36 /* System library. */ 37 38 #include <sys_defs.h> /* includes <sys/types.h> */ 39 #include <sys/socket.h> 40 #include <sys/uio.h> 41 #include <string.h> 42 43 /* Utility library. */ 44 45 #include <msg.h> 46 #include <iostuff.h> 47 48 /* unix_send_fd - send file descriptor */ 49 50 int unix_send_fd(int fd, int sendfd) 51 { 52 53 /* 54 * This code does not work with version <2.2 Linux kernels, and it does 55 * not compile with version <2 Linux libraries. 56 */ 57 #ifdef CANT_USE_SEND_RECV_MSG 58 const char *myname = "unix_send_fd"; 59 60 msg_warn("%s: your system has no support for file descriptor passing", 61 myname); 62 return (-1); 63 #else 64 struct msghdr msg; 65 struct iovec iov[1]; 66 67 /* 68 * Adapted from: W. Richard Stevens, UNIX Network Programming, Volume 1, 69 * Second edition. Except that we use CMSG_LEN instead of CMSG_SPACE; the 70 * latter breaks on LP64 systems. 71 */ 72 #if defined(CMSG_SPACE) && !defined(NO_MSGHDR_MSG_CONTROL) 73 union { 74 struct cmsghdr just_for_alignment; 75 char control[CMSG_SPACE(sizeof(sendfd))]; 76 } control_un; 77 struct cmsghdr *cmptr; 78 79 memset((char *) &msg, 0, sizeof(msg)); /* Fix 200512 */ 80 msg.msg_control = control_un.control; 81 msg.msg_controllen = sizeof(control_un.control); /* Fix 200506 */ 82 83 cmptr = CMSG_FIRSTHDR(&msg); 84 cmptr->cmsg_len = CMSG_LEN(sizeof(sendfd)); 85 cmptr->cmsg_level = SOL_SOCKET; 86 cmptr->cmsg_type = SCM_RIGHTS; 87 *(int *) CMSG_DATA(cmptr) = sendfd; 88 #else 89 msg.msg_accrights = (char *) &sendfd; 90 msg.msg_accrightslen = sizeof(sendfd); 91 #endif 92 93 msg.msg_name = 0; 94 msg.msg_namelen = 0; 95 96 /* 97 * XXX We don't want to pass any data, just a file descriptor. However, 98 * setting msg.msg_iov = 0 and msg.msg_iovlen = 0 causes trouble. See the 99 * comments in the unix_recv_fd() routine. 100 */ 101 iov->iov_base = ""; 102 iov->iov_len = 1; 103 msg.msg_iov = iov; 104 msg.msg_iovlen = 1; 105 106 return (sendmsg(fd, &msg, 0)); 107 #endif 108 } 109 110 #ifdef TEST 111 112 /* 113 * Proof-of-concept program. Open a file and send the descriptor, presumably 114 * to the unix_recv_fd test program. 115 */ 116 #include <unistd.h> 117 #include <string.h> 118 #include <stdlib.h> 119 #include <fcntl.h> 120 #include <split_at.h> 121 #include <connect.h> 122 123 int main(int argc, char **argv) 124 { 125 char *transport; 126 char *endpoint; 127 char *path; 128 int server_sock; 129 int client_fd; 130 131 if (argc < 3 132 || (endpoint = split_at(transport = argv[1], ':')) == 0 133 || *endpoint == 0 || *transport == 0) 134 msg_fatal("usage: %s transport:endpoint file...", argv[0]); 135 136 if (strcmp(transport, "unix") == 0) { 137 server_sock = unix_connect(endpoint, BLOCKING, 0); 138 } else { 139 msg_fatal("invalid transport name: %s", transport); 140 } 141 if (server_sock < 0) 142 msg_fatal("connect %s:%s: %m", transport, endpoint); 143 144 argv += 2; 145 while ((path = *argv++) != 0) { 146 if ((client_fd = open(path, O_RDONLY, 0)) < 0) 147 msg_fatal("open %s: %m", path); 148 msg_info("path=%s fd=%d", path, client_fd); 149 if (unix_send_fd(server_sock, client_fd) < 0) 150 msg_fatal("send file descriptor: %m"); 151 if (close(client_fd) != 0) 152 msg_fatal("close(%d): %m", client_fd); 153 } 154 exit(0); 155 } 156 157 #endif 158