1*aa772005SRobert Watson /*- 2*aa772005SRobert Watson * Copyright (c) 2009-2010 The FreeBSD Foundation 3*aa772005SRobert Watson * All rights reserved. 4*aa772005SRobert Watson * 5*aa772005SRobert Watson * This software was developed by Pawel Jakub Dawidek under sponsorship from 6*aa772005SRobert Watson * the FreeBSD Foundation. 7*aa772005SRobert Watson * 8*aa772005SRobert Watson * Redistribution and use in source and binary forms, with or without 9*aa772005SRobert Watson * modification, are permitted provided that the following conditions 10*aa772005SRobert Watson * are met: 11*aa772005SRobert Watson * 1. Redistributions of source code must retain the above copyright 12*aa772005SRobert Watson * notice, this list of conditions and the following disclaimer. 13*aa772005SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 14*aa772005SRobert Watson * notice, this list of conditions and the following disclaimer in the 15*aa772005SRobert Watson * documentation and/or other materials provided with the distribution. 16*aa772005SRobert Watson * 17*aa772005SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18*aa772005SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19*aa772005SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20*aa772005SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21*aa772005SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22*aa772005SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23*aa772005SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24*aa772005SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25*aa772005SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26*aa772005SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27*aa772005SRobert Watson * SUCH DAMAGE. 28*aa772005SRobert Watson * 29*aa772005SRobert Watson * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/proto_socketpair.c#1 $ 30*aa772005SRobert Watson */ 31*aa772005SRobert Watson 32*aa772005SRobert Watson #include <sys/types.h> 33*aa772005SRobert Watson #include <sys/socket.h> 34*aa772005SRobert Watson 35*aa772005SRobert Watson #include <errno.h> 36*aa772005SRobert Watson #include <stdbool.h> 37*aa772005SRobert Watson #include <stdint.h> 38*aa772005SRobert Watson #include <stdio.h> 39*aa772005SRobert Watson #include <string.h> 40*aa772005SRobert Watson #include <unistd.h> 41*aa772005SRobert Watson 42*aa772005SRobert Watson #include "pjdlog.h" 43*aa772005SRobert Watson #include "proto_impl.h" 44*aa772005SRobert Watson 45*aa772005SRobert Watson #define SP_CTX_MAGIC 0x50c3741 46*aa772005SRobert Watson struct sp_ctx { 47*aa772005SRobert Watson int sp_magic; 48*aa772005SRobert Watson int sp_fd[2]; 49*aa772005SRobert Watson int sp_side; 50*aa772005SRobert Watson #define SP_SIDE_UNDEF 0 51*aa772005SRobert Watson #define SP_SIDE_CLIENT 1 52*aa772005SRobert Watson #define SP_SIDE_SERVER 2 53*aa772005SRobert Watson }; 54*aa772005SRobert Watson 55*aa772005SRobert Watson static void sp_close(void *ctx); 56*aa772005SRobert Watson 57*aa772005SRobert Watson static int 58*aa772005SRobert Watson sp_connect(const char *srcaddr, const char *dstaddr, int timeout, void **ctxp) 59*aa772005SRobert Watson { 60*aa772005SRobert Watson struct sp_ctx *spctx; 61*aa772005SRobert Watson int error; 62*aa772005SRobert Watson 63*aa772005SRobert Watson PJDLOG_ASSERT(dstaddr != NULL); 64*aa772005SRobert Watson PJDLOG_ASSERT(timeout >= -1); 65*aa772005SRobert Watson 66*aa772005SRobert Watson if (strcmp(dstaddr, "socketpair://") != 0) 67*aa772005SRobert Watson return (-1); 68*aa772005SRobert Watson 69*aa772005SRobert Watson PJDLOG_ASSERT(srcaddr == NULL); 70*aa772005SRobert Watson 71*aa772005SRobert Watson spctx = malloc(sizeof(*spctx)); 72*aa772005SRobert Watson if (spctx == NULL) 73*aa772005SRobert Watson return (errno); 74*aa772005SRobert Watson 75*aa772005SRobert Watson if (socketpair(PF_UNIX, SOCK_STREAM, 0, spctx->sp_fd) == -1) { 76*aa772005SRobert Watson error = errno; 77*aa772005SRobert Watson free(spctx); 78*aa772005SRobert Watson return (error); 79*aa772005SRobert Watson } 80*aa772005SRobert Watson 81*aa772005SRobert Watson spctx->sp_side = SP_SIDE_UNDEF; 82*aa772005SRobert Watson spctx->sp_magic = SP_CTX_MAGIC; 83*aa772005SRobert Watson *ctxp = spctx; 84*aa772005SRobert Watson 85*aa772005SRobert Watson return (0); 86*aa772005SRobert Watson } 87*aa772005SRobert Watson 88*aa772005SRobert Watson static int 89*aa772005SRobert Watson sp_wrap(int fd, bool client, void **ctxp) 90*aa772005SRobert Watson { 91*aa772005SRobert Watson struct sp_ctx *spctx; 92*aa772005SRobert Watson 93*aa772005SRobert Watson PJDLOG_ASSERT(fd >= 0); 94*aa772005SRobert Watson 95*aa772005SRobert Watson spctx = malloc(sizeof(*spctx)); 96*aa772005SRobert Watson if (spctx == NULL) 97*aa772005SRobert Watson return (errno); 98*aa772005SRobert Watson 99*aa772005SRobert Watson if (client) { 100*aa772005SRobert Watson spctx->sp_side = SP_SIDE_CLIENT; 101*aa772005SRobert Watson spctx->sp_fd[0] = fd; 102*aa772005SRobert Watson spctx->sp_fd[1] = -1; 103*aa772005SRobert Watson } else { 104*aa772005SRobert Watson spctx->sp_side = SP_SIDE_SERVER; 105*aa772005SRobert Watson spctx->sp_fd[0] = -1; 106*aa772005SRobert Watson spctx->sp_fd[1] = fd; 107*aa772005SRobert Watson } 108*aa772005SRobert Watson spctx->sp_magic = SP_CTX_MAGIC; 109*aa772005SRobert Watson *ctxp = spctx; 110*aa772005SRobert Watson 111*aa772005SRobert Watson return (0); 112*aa772005SRobert Watson } 113*aa772005SRobert Watson 114*aa772005SRobert Watson static int 115*aa772005SRobert Watson sp_send(void *ctx, const unsigned char *data, size_t size, int fd) 116*aa772005SRobert Watson { 117*aa772005SRobert Watson struct sp_ctx *spctx = ctx; 118*aa772005SRobert Watson int sock; 119*aa772005SRobert Watson 120*aa772005SRobert Watson PJDLOG_ASSERT(spctx != NULL); 121*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC); 122*aa772005SRobert Watson 123*aa772005SRobert Watson switch (spctx->sp_side) { 124*aa772005SRobert Watson case SP_SIDE_UNDEF: 125*aa772005SRobert Watson /* 126*aa772005SRobert Watson * If the first operation done by the caller is proto_send(), 127*aa772005SRobert Watson * we assume this is the client. 128*aa772005SRobert Watson */ 129*aa772005SRobert Watson /* FALLTHROUGH */ 130*aa772005SRobert Watson spctx->sp_side = SP_SIDE_CLIENT; 131*aa772005SRobert Watson /* Close other end. */ 132*aa772005SRobert Watson close(spctx->sp_fd[1]); 133*aa772005SRobert Watson spctx->sp_fd[1] = -1; 134*aa772005SRobert Watson case SP_SIDE_CLIENT: 135*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[0] >= 0); 136*aa772005SRobert Watson sock = spctx->sp_fd[0]; 137*aa772005SRobert Watson break; 138*aa772005SRobert Watson case SP_SIDE_SERVER: 139*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[1] >= 0); 140*aa772005SRobert Watson sock = spctx->sp_fd[1]; 141*aa772005SRobert Watson break; 142*aa772005SRobert Watson default: 143*aa772005SRobert Watson PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side); 144*aa772005SRobert Watson } 145*aa772005SRobert Watson 146*aa772005SRobert Watson /* Someone is just trying to decide about side. */ 147*aa772005SRobert Watson if (data == NULL) 148*aa772005SRobert Watson return (0); 149*aa772005SRobert Watson 150*aa772005SRobert Watson return (proto_common_send(sock, data, size, fd)); 151*aa772005SRobert Watson } 152*aa772005SRobert Watson 153*aa772005SRobert Watson static int 154*aa772005SRobert Watson sp_recv(void *ctx, unsigned char *data, size_t size, int *fdp) 155*aa772005SRobert Watson { 156*aa772005SRobert Watson struct sp_ctx *spctx = ctx; 157*aa772005SRobert Watson int sock; 158*aa772005SRobert Watson 159*aa772005SRobert Watson PJDLOG_ASSERT(spctx != NULL); 160*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC); 161*aa772005SRobert Watson 162*aa772005SRobert Watson switch (spctx->sp_side) { 163*aa772005SRobert Watson case SP_SIDE_UNDEF: 164*aa772005SRobert Watson /* 165*aa772005SRobert Watson * If the first operation done by the caller is proto_recv(), 166*aa772005SRobert Watson * we assume this is the server. 167*aa772005SRobert Watson */ 168*aa772005SRobert Watson /* FALLTHROUGH */ 169*aa772005SRobert Watson spctx->sp_side = SP_SIDE_SERVER; 170*aa772005SRobert Watson /* Close other end. */ 171*aa772005SRobert Watson close(spctx->sp_fd[0]); 172*aa772005SRobert Watson spctx->sp_fd[0] = -1; 173*aa772005SRobert Watson case SP_SIDE_SERVER: 174*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[1] >= 0); 175*aa772005SRobert Watson sock = spctx->sp_fd[1]; 176*aa772005SRobert Watson break; 177*aa772005SRobert Watson case SP_SIDE_CLIENT: 178*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[0] >= 0); 179*aa772005SRobert Watson sock = spctx->sp_fd[0]; 180*aa772005SRobert Watson break; 181*aa772005SRobert Watson default: 182*aa772005SRobert Watson PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side); 183*aa772005SRobert Watson } 184*aa772005SRobert Watson 185*aa772005SRobert Watson /* Someone is just trying to decide about side. */ 186*aa772005SRobert Watson if (data == NULL) 187*aa772005SRobert Watson return (0); 188*aa772005SRobert Watson 189*aa772005SRobert Watson return (proto_common_recv(sock, data, size, fdp)); 190*aa772005SRobert Watson } 191*aa772005SRobert Watson 192*aa772005SRobert Watson static int 193*aa772005SRobert Watson sp_descriptor(const void *ctx) 194*aa772005SRobert Watson { 195*aa772005SRobert Watson const struct sp_ctx *spctx = ctx; 196*aa772005SRobert Watson 197*aa772005SRobert Watson PJDLOG_ASSERT(spctx != NULL); 198*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC); 199*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_side == SP_SIDE_CLIENT || 200*aa772005SRobert Watson spctx->sp_side == SP_SIDE_SERVER); 201*aa772005SRobert Watson 202*aa772005SRobert Watson switch (spctx->sp_side) { 203*aa772005SRobert Watson case SP_SIDE_CLIENT: 204*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[0] >= 0); 205*aa772005SRobert Watson return (spctx->sp_fd[0]); 206*aa772005SRobert Watson case SP_SIDE_SERVER: 207*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[1] >= 0); 208*aa772005SRobert Watson return (spctx->sp_fd[1]); 209*aa772005SRobert Watson } 210*aa772005SRobert Watson 211*aa772005SRobert Watson PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side); 212*aa772005SRobert Watson } 213*aa772005SRobert Watson 214*aa772005SRobert Watson static void 215*aa772005SRobert Watson sp_close(void *ctx) 216*aa772005SRobert Watson { 217*aa772005SRobert Watson struct sp_ctx *spctx = ctx; 218*aa772005SRobert Watson 219*aa772005SRobert Watson PJDLOG_ASSERT(spctx != NULL); 220*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC); 221*aa772005SRobert Watson 222*aa772005SRobert Watson switch (spctx->sp_side) { 223*aa772005SRobert Watson case SP_SIDE_UNDEF: 224*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[0] >= 0); 225*aa772005SRobert Watson close(spctx->sp_fd[0]); 226*aa772005SRobert Watson spctx->sp_fd[0] = -1; 227*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[1] >= 0); 228*aa772005SRobert Watson close(spctx->sp_fd[1]); 229*aa772005SRobert Watson spctx->sp_fd[1] = -1; 230*aa772005SRobert Watson break; 231*aa772005SRobert Watson case SP_SIDE_CLIENT: 232*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[0] >= 0); 233*aa772005SRobert Watson close(spctx->sp_fd[0]); 234*aa772005SRobert Watson spctx->sp_fd[0] = -1; 235*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[1] == -1); 236*aa772005SRobert Watson break; 237*aa772005SRobert Watson case SP_SIDE_SERVER: 238*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[1] >= 0); 239*aa772005SRobert Watson close(spctx->sp_fd[1]); 240*aa772005SRobert Watson spctx->sp_fd[1] = -1; 241*aa772005SRobert Watson PJDLOG_ASSERT(spctx->sp_fd[0] == -1); 242*aa772005SRobert Watson break; 243*aa772005SRobert Watson default: 244*aa772005SRobert Watson PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side); 245*aa772005SRobert Watson } 246*aa772005SRobert Watson 247*aa772005SRobert Watson spctx->sp_magic = 0; 248*aa772005SRobert Watson free(spctx); 249*aa772005SRobert Watson } 250*aa772005SRobert Watson 251*aa772005SRobert Watson static struct proto sp_proto = { 252*aa772005SRobert Watson .prt_name = "socketpair", 253*aa772005SRobert Watson .prt_connect = sp_connect, 254*aa772005SRobert Watson .prt_wrap = sp_wrap, 255*aa772005SRobert Watson .prt_send = sp_send, 256*aa772005SRobert Watson .prt_recv = sp_recv, 257*aa772005SRobert Watson .prt_descriptor = sp_descriptor, 258*aa772005SRobert Watson .prt_close = sp_close 259*aa772005SRobert Watson }; 260*aa772005SRobert Watson 261*aa772005SRobert Watson static __constructor void 262*aa772005SRobert Watson sp_ctor(void) 263*aa772005SRobert Watson { 264*aa772005SRobert Watson 265*aa772005SRobert Watson proto_register(&sp_proto, false); 266*aa772005SRobert Watson } 267