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