xref: /freebsd/contrib/openbsm/bin/auditdistd/proto_socketpair.c (revision aa77200569e397d6ff1fdb4d255d0fa254d0a128)
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