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