1243730Srwatson/*-
2243730Srwatson * Copyright (c) 2009-2010 The FreeBSD Foundation
3243730Srwatson * All rights reserved.
4243730Srwatson *
5243730Srwatson * This software was developed by Pawel Jakub Dawidek under sponsorship from
6243730Srwatson * the FreeBSD Foundation.
7243730Srwatson *
8243730Srwatson * Redistribution and use in source and binary forms, with or without
9243730Srwatson * modification, are permitted provided that the following conditions
10243730Srwatson * are met:
11243730Srwatson * 1. Redistributions of source code must retain the above copyright
12243730Srwatson *    notice, this list of conditions and the following disclaimer.
13243730Srwatson * 2. Redistributions in binary form must reproduce the above copyright
14243730Srwatson *    notice, this list of conditions and the following disclaimer in the
15243730Srwatson *    documentation and/or other materials provided with the distribution.
16243730Srwatson *
17243730Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
18243730Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19243730Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20243730Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE
21243730Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22243730Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23243730Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24243730Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25243730Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26243730Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27243730Srwatson * SUCH DAMAGE.
28243730Srwatson *
29243730Srwatson * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/proto_socketpair.c#1 $
30243730Srwatson */
31243730Srwatson
32243730Srwatson#include <sys/types.h>
33243730Srwatson#include <sys/socket.h>
34243730Srwatson
35243730Srwatson#include <errno.h>
36243730Srwatson#include <stdbool.h>
37243730Srwatson#include <stdint.h>
38243730Srwatson#include <stdio.h>
39243730Srwatson#include <string.h>
40243730Srwatson#include <unistd.h>
41243730Srwatson
42243730Srwatson#include "pjdlog.h"
43243730Srwatson#include "proto_impl.h"
44243730Srwatson
45243730Srwatson#define	SP_CTX_MAGIC	0x50c3741
46243730Srwatsonstruct sp_ctx {
47243730Srwatson	int			sp_magic;
48243730Srwatson	int			sp_fd[2];
49243730Srwatson	int			sp_side;
50243730Srwatson#define	SP_SIDE_UNDEF		0
51243730Srwatson#define	SP_SIDE_CLIENT		1
52243730Srwatson#define	SP_SIDE_SERVER		2
53243730Srwatson};
54243730Srwatson
55243730Srwatsonstatic void sp_close(void *ctx);
56243730Srwatson
57243730Srwatsonstatic int
58243730Srwatsonsp_connect(const char *srcaddr, const char *dstaddr, int timeout, void **ctxp)
59243730Srwatson{
60243730Srwatson	struct sp_ctx *spctx;
61243730Srwatson	int error;
62243730Srwatson
63243730Srwatson	PJDLOG_ASSERT(dstaddr != NULL);
64243730Srwatson	PJDLOG_ASSERT(timeout >= -1);
65243730Srwatson
66243730Srwatson	if (strcmp(dstaddr, "socketpair://") != 0)
67243730Srwatson		return (-1);
68243730Srwatson
69243730Srwatson	PJDLOG_ASSERT(srcaddr == NULL);
70243730Srwatson
71243730Srwatson	spctx = malloc(sizeof(*spctx));
72243730Srwatson	if (spctx == NULL)
73243730Srwatson		return (errno);
74243730Srwatson
75243730Srwatson	if (socketpair(PF_UNIX, SOCK_STREAM, 0, spctx->sp_fd) == -1) {
76243730Srwatson		error = errno;
77243730Srwatson		free(spctx);
78243730Srwatson		return (error);
79243730Srwatson	}
80243730Srwatson
81243730Srwatson	spctx->sp_side = SP_SIDE_UNDEF;
82243730Srwatson	spctx->sp_magic = SP_CTX_MAGIC;
83243730Srwatson	*ctxp = spctx;
84243730Srwatson
85243730Srwatson	return (0);
86243730Srwatson}
87243730Srwatson
88243730Srwatsonstatic int
89243730Srwatsonsp_wrap(int fd, bool client, void **ctxp)
90243730Srwatson{
91243730Srwatson	struct sp_ctx *spctx;
92243730Srwatson
93243730Srwatson	PJDLOG_ASSERT(fd >= 0);
94243730Srwatson
95243730Srwatson	spctx = malloc(sizeof(*spctx));
96243730Srwatson	if (spctx == NULL)
97243730Srwatson		return (errno);
98243730Srwatson
99243730Srwatson	if (client) {
100243730Srwatson		spctx->sp_side = SP_SIDE_CLIENT;
101243730Srwatson		spctx->sp_fd[0] = fd;
102243730Srwatson		spctx->sp_fd[1] = -1;
103243730Srwatson	} else {
104243730Srwatson		spctx->sp_side = SP_SIDE_SERVER;
105243730Srwatson		spctx->sp_fd[0] = -1;
106243730Srwatson		spctx->sp_fd[1] = fd;
107243730Srwatson	}
108243730Srwatson	spctx->sp_magic = SP_CTX_MAGIC;
109243730Srwatson	*ctxp = spctx;
110243730Srwatson
111243730Srwatson	return (0);
112243730Srwatson}
113243730Srwatson
114243730Srwatsonstatic int
115243730Srwatsonsp_send(void *ctx, const unsigned char *data, size_t size, int fd)
116243730Srwatson{
117243730Srwatson	struct sp_ctx *spctx = ctx;
118243730Srwatson	int sock;
119243730Srwatson
120243730Srwatson	PJDLOG_ASSERT(spctx != NULL);
121243730Srwatson	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
122243730Srwatson
123243730Srwatson	switch (spctx->sp_side) {
124243730Srwatson	case SP_SIDE_UNDEF:
125243730Srwatson		/*
126243730Srwatson		 * If the first operation done by the caller is proto_send(),
127243730Srwatson		 * we assume this is the client.
128243730Srwatson		 */
129243730Srwatson		/* FALLTHROUGH */
130243730Srwatson		spctx->sp_side = SP_SIDE_CLIENT;
131243730Srwatson		/* Close other end. */
132243730Srwatson		close(spctx->sp_fd[1]);
133243730Srwatson		spctx->sp_fd[1] = -1;
134243730Srwatson	case SP_SIDE_CLIENT:
135243730Srwatson		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
136243730Srwatson		sock = spctx->sp_fd[0];
137243730Srwatson		break;
138243730Srwatson	case SP_SIDE_SERVER:
139243730Srwatson		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
140243730Srwatson		sock = spctx->sp_fd[1];
141243730Srwatson		break;
142243730Srwatson	default:
143243730Srwatson		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
144243730Srwatson	}
145243730Srwatson
146243730Srwatson	/* Someone is just trying to decide about side. */
147243730Srwatson	if (data == NULL)
148243730Srwatson		return (0);
149243730Srwatson
150243730Srwatson	return (proto_common_send(sock, data, size, fd));
151243730Srwatson}
152243730Srwatson
153243730Srwatsonstatic int
154243730Srwatsonsp_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
155243730Srwatson{
156243730Srwatson	struct sp_ctx *spctx = ctx;
157243730Srwatson	int sock;
158243730Srwatson
159243730Srwatson	PJDLOG_ASSERT(spctx != NULL);
160243730Srwatson	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
161243730Srwatson
162243730Srwatson	switch (spctx->sp_side) {
163243730Srwatson	case SP_SIDE_UNDEF:
164243730Srwatson		/*
165243730Srwatson		 * If the first operation done by the caller is proto_recv(),
166243730Srwatson		 * we assume this is the server.
167243730Srwatson		 */
168243730Srwatson		/* FALLTHROUGH */
169243730Srwatson		spctx->sp_side = SP_SIDE_SERVER;
170243730Srwatson		/* Close other end. */
171243730Srwatson		close(spctx->sp_fd[0]);
172243730Srwatson		spctx->sp_fd[0] = -1;
173243730Srwatson	case SP_SIDE_SERVER:
174243730Srwatson		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
175243730Srwatson		sock = spctx->sp_fd[1];
176243730Srwatson		break;
177243730Srwatson	case SP_SIDE_CLIENT:
178243730Srwatson		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
179243730Srwatson		sock = spctx->sp_fd[0];
180243730Srwatson		break;
181243730Srwatson	default:
182243730Srwatson		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
183243730Srwatson	}
184243730Srwatson
185243730Srwatson	/* Someone is just trying to decide about side. */
186243730Srwatson	if (data == NULL)
187243730Srwatson		return (0);
188243730Srwatson
189243730Srwatson	return (proto_common_recv(sock, data, size, fdp));
190243730Srwatson}
191243730Srwatson
192243730Srwatsonstatic int
193243730Srwatsonsp_descriptor(const void *ctx)
194243730Srwatson{
195243730Srwatson	const struct sp_ctx *spctx = ctx;
196243730Srwatson
197243730Srwatson	PJDLOG_ASSERT(spctx != NULL);
198243730Srwatson	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
199243730Srwatson	PJDLOG_ASSERT(spctx->sp_side == SP_SIDE_CLIENT ||
200243730Srwatson	    spctx->sp_side == SP_SIDE_SERVER);
201243730Srwatson
202243730Srwatson	switch (spctx->sp_side) {
203243730Srwatson	case SP_SIDE_CLIENT:
204243730Srwatson		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
205243730Srwatson		return (spctx->sp_fd[0]);
206243730Srwatson	case SP_SIDE_SERVER:
207243730Srwatson		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
208243730Srwatson		return (spctx->sp_fd[1]);
209243730Srwatson	}
210243730Srwatson
211243730Srwatson	PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
212243730Srwatson}
213243730Srwatson
214243730Srwatsonstatic void
215243730Srwatsonsp_close(void *ctx)
216243730Srwatson{
217243730Srwatson	struct sp_ctx *spctx = ctx;
218243730Srwatson
219243730Srwatson	PJDLOG_ASSERT(spctx != NULL);
220243730Srwatson	PJDLOG_ASSERT(spctx->sp_magic == SP_CTX_MAGIC);
221243730Srwatson
222243730Srwatson	switch (spctx->sp_side) {
223243730Srwatson	case SP_SIDE_UNDEF:
224243730Srwatson		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
225243730Srwatson		close(spctx->sp_fd[0]);
226243730Srwatson		spctx->sp_fd[0] = -1;
227243730Srwatson		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
228243730Srwatson		close(spctx->sp_fd[1]);
229243730Srwatson		spctx->sp_fd[1] = -1;
230243730Srwatson		break;
231243730Srwatson	case SP_SIDE_CLIENT:
232243730Srwatson		PJDLOG_ASSERT(spctx->sp_fd[0] >= 0);
233243730Srwatson		close(spctx->sp_fd[0]);
234243730Srwatson		spctx->sp_fd[0] = -1;
235243730Srwatson		PJDLOG_ASSERT(spctx->sp_fd[1] == -1);
236243730Srwatson		break;
237243730Srwatson	case SP_SIDE_SERVER:
238243730Srwatson		PJDLOG_ASSERT(spctx->sp_fd[1] >= 0);
239243730Srwatson		close(spctx->sp_fd[1]);
240243730Srwatson		spctx->sp_fd[1] = -1;
241243730Srwatson		PJDLOG_ASSERT(spctx->sp_fd[0] == -1);
242243730Srwatson		break;
243243730Srwatson	default:
244243730Srwatson		PJDLOG_ABORT("Invalid socket side (%d).", spctx->sp_side);
245243730Srwatson	}
246243730Srwatson
247243730Srwatson	spctx->sp_magic = 0;
248243730Srwatson	free(spctx);
249243730Srwatson}
250243730Srwatson
251243730Srwatsonstatic struct proto sp_proto = {
252243730Srwatson	.prt_name = "socketpair",
253243730Srwatson	.prt_connect = sp_connect,
254243730Srwatson	.prt_wrap = sp_wrap,
255243730Srwatson	.prt_send = sp_send,
256243730Srwatson	.prt_recv = sp_recv,
257243730Srwatson	.prt_descriptor = sp_descriptor,
258243730Srwatson	.prt_close = sp_close
259243730Srwatson};
260243730Srwatson
261243730Srwatsonstatic __constructor void
262243730Srwatsonsp_ctor(void)
263243730Srwatson{
264243730Srwatson
265243730Srwatson	proto_register(&sp_proto, false);
266243730Srwatson}
267