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 *
29243734Srwatson * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/proto_uds.c#2 $
30243730Srwatson */
31243730Srwatson
32243730Srwatson/* UDS - UNIX Domain Socket */
33243730Srwatson
34243734Srwatson#include <config/config.h>
35243730Srwatson
36243730Srwatson#include <sys/types.h>
37243730Srwatson#include <sys/socket.h>
38243730Srwatson#include <sys/un.h>
39243730Srwatson
40243730Srwatson#include <errno.h>
41243730Srwatson#include <stdbool.h>
42243730Srwatson#include <stdint.h>
43243730Srwatson#include <stdio.h>
44243730Srwatson#include <string.h>
45243730Srwatson#include <unistd.h>
46243730Srwatson
47243730Srwatson#ifndef HAVE_STRLCPY
48243730Srwatson#include <compat/strlcpy.h>
49243730Srwatson#endif
50243730Srwatson
51243730Srwatson#include "pjdlog.h"
52243730Srwatson#include "proto_impl.h"
53243730Srwatson
54243730Srwatson#define	UDS_CTX_MAGIC	0xd541c
55243730Srwatsonstruct uds_ctx {
56243730Srwatson	int			uc_magic;
57243730Srwatson	struct sockaddr_un	uc_sun;
58243730Srwatson	int			uc_fd;
59243730Srwatson	int			uc_side;
60243730Srwatson#define	UDS_SIDE_CLIENT		0
61243730Srwatson#define	UDS_SIDE_SERVER_LISTEN	1
62243730Srwatson#define	UDS_SIDE_SERVER_WORK	2
63243730Srwatson	pid_t			uc_owner;
64243730Srwatson};
65243730Srwatson
66243730Srwatsonstatic void uds_close(void *ctx);
67243730Srwatson
68243730Srwatsonstatic int
69243730Srwatsonuds_addr(const char *addr, struct sockaddr_un *sunp)
70243730Srwatson{
71243730Srwatson
72243730Srwatson	if (addr == NULL)
73243730Srwatson		return (-1);
74243730Srwatson
75243730Srwatson	if (strncasecmp(addr, "uds://", 6) == 0)
76243730Srwatson		addr += 6;
77243730Srwatson	else if (strncasecmp(addr, "unix://", 7) == 0)
78243730Srwatson		addr += 7;
79243730Srwatson	else if (addr[0] == '/' &&	/* If it starts from /... */
80243730Srwatson	    strstr(addr, "://") == NULL)/* ...and there is no prefix... */
81243730Srwatson		;			/* ...we assume its us. */
82243730Srwatson	else
83243730Srwatson		return (-1);
84243730Srwatson
85243730Srwatson	sunp->sun_family = AF_UNIX;
86243730Srwatson	if (strlcpy(sunp->sun_path, addr, sizeof(sunp->sun_path)) >=
87243730Srwatson	    sizeof(sunp->sun_path)) {
88243730Srwatson		return (ENAMETOOLONG);
89243730Srwatson	}
90243730Srwatson#ifdef HAVE_SOCKADDR_STORAGE_SS_LEN
91243730Srwatson	sunp->sun_len = SUN_LEN(sunp);
92243730Srwatson#endif
93243730Srwatson
94243730Srwatson	return (0);
95243730Srwatson}
96243730Srwatson
97243730Srwatsonstatic int
98243730Srwatsonuds_common_setup(const char *addr, int side, struct uds_ctx **uctxp)
99243730Srwatson{
100243730Srwatson	struct uds_ctx *uctx;
101243730Srwatson	int error;
102243730Srwatson
103243730Srwatson	uctx = malloc(sizeof(*uctx));
104243730Srwatson	if (uctx == NULL)
105243730Srwatson		return (errno);
106243730Srwatson
107243730Srwatson	/* Parse given address. */
108243730Srwatson	error = uds_addr(addr, &uctx->uc_sun);
109243730Srwatson	if (error != 0) {
110243730Srwatson		free(uctx);
111243730Srwatson		return (error);
112243730Srwatson	}
113243730Srwatson
114243730Srwatson	uctx->uc_fd = socket(AF_UNIX, SOCK_STREAM, 0);
115243730Srwatson	if (uctx->uc_fd == -1) {
116243730Srwatson		error = errno;
117243730Srwatson		free(uctx);
118243730Srwatson		return (error);
119243730Srwatson	}
120243730Srwatson
121243730Srwatson	uctx->uc_side = side;
122243730Srwatson	uctx->uc_owner = 0;
123243730Srwatson	uctx->uc_magic = UDS_CTX_MAGIC;
124243730Srwatson	*uctxp = uctx;
125243730Srwatson
126243730Srwatson	return (0);
127243730Srwatson}
128243730Srwatson
129243730Srwatsonstatic int
130243730Srwatsonuds_connect(const char *srcaddr, const char *dstaddr, int timeout, void **ctxp)
131243730Srwatson{
132243730Srwatson	struct uds_ctx *uctx;
133243730Srwatson	int error;
134243730Srwatson
135243730Srwatson	PJDLOG_ASSERT(dstaddr != NULL);
136243730Srwatson	PJDLOG_ASSERT(timeout >= -1);
137243730Srwatson
138243730Srwatson	error = uds_common_setup(dstaddr, UDS_SIDE_CLIENT, &uctx);
139243730Srwatson	if (error != 0)
140243730Srwatson		return (error);
141243730Srwatson
142243730Srwatson	PJDLOG_ASSERT(srcaddr == NULL);
143243730Srwatson
144243730Srwatson	if (connect(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
145243730Srwatson	    sizeof(uctx->uc_sun)) == -1) {
146243730Srwatson		error = errno;
147243730Srwatson		uds_close(uctx);
148243730Srwatson		return (error);
149243730Srwatson	}
150243730Srwatson
151243730Srwatson	*ctxp = uctx;
152243730Srwatson
153243730Srwatson	return (0);
154243730Srwatson}
155243730Srwatson
156243730Srwatsonstatic int
157243730Srwatsonuds_connect_wait(void *ctx, int timeout)
158243730Srwatson{
159243730Srwatson	struct uds_ctx *uctx = ctx;
160243730Srwatson
161243730Srwatson	PJDLOG_ASSERT(uctx != NULL);
162243730Srwatson	PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
163243730Srwatson	PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT);
164243730Srwatson	PJDLOG_ASSERT(uctx->uc_fd >= 0);
165243730Srwatson	PJDLOG_ASSERT(timeout >= 0);
166243730Srwatson
167243730Srwatson	return (0);
168243730Srwatson}
169243730Srwatson
170243730Srwatsonstatic int
171243730Srwatsonuds_server(const char *addr, void **ctxp)
172243730Srwatson{
173243730Srwatson	struct uds_ctx *uctx;
174243730Srwatson	int error;
175243730Srwatson
176243730Srwatson	error = uds_common_setup(addr, UDS_SIDE_SERVER_LISTEN, &uctx);
177243730Srwatson	if (error != 0)
178243730Srwatson		return (error);
179243730Srwatson
180243730Srwatson	(void)unlink(uctx->uc_sun.sun_path);
181243730Srwatson	if (bind(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
182243730Srwatson	    sizeof(uctx->uc_sun)) == -1) {
183243730Srwatson		error = errno;
184243730Srwatson		uds_close(uctx);
185243730Srwatson		return (error);
186243730Srwatson	}
187243730Srwatson	uctx->uc_owner = getpid();
188243730Srwatson	if (listen(uctx->uc_fd, 8) == -1) {
189243730Srwatson		error = errno;
190243730Srwatson		uds_close(uctx);
191243730Srwatson		return (error);
192243730Srwatson	}
193243730Srwatson
194243730Srwatson	*ctxp = uctx;
195243730Srwatson
196243730Srwatson	return (0);
197243730Srwatson}
198243730Srwatson
199243730Srwatsonstatic int
200243730Srwatsonuds_accept(void *ctx, void **newctxp)
201243730Srwatson{
202243730Srwatson	struct uds_ctx *uctx = ctx;
203243730Srwatson	struct uds_ctx *newuctx;
204243730Srwatson	socklen_t fromlen;
205243730Srwatson	int error;
206243730Srwatson
207243730Srwatson	PJDLOG_ASSERT(uctx != NULL);
208243730Srwatson	PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
209243730Srwatson	PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_SERVER_LISTEN);
210243730Srwatson	PJDLOG_ASSERT(uctx->uc_fd >= 0);
211243730Srwatson
212243730Srwatson	newuctx = malloc(sizeof(*newuctx));
213243730Srwatson	if (newuctx == NULL)
214243730Srwatson		return (errno);
215243730Srwatson
216243730Srwatson	fromlen = sizeof(newuctx->uc_sun);
217243730Srwatson	newuctx->uc_fd = accept(uctx->uc_fd,
218243730Srwatson	    (struct sockaddr *)&newuctx->uc_sun, &fromlen);
219243730Srwatson	if (newuctx->uc_fd < 0) {
220243730Srwatson		error = errno;
221243730Srwatson		free(newuctx);
222243730Srwatson		return (error);
223243730Srwatson	}
224243730Srwatson
225243730Srwatson	newuctx->uc_side = UDS_SIDE_SERVER_WORK;
226243730Srwatson	newuctx->uc_magic = UDS_CTX_MAGIC;
227243730Srwatson	*newctxp = newuctx;
228243730Srwatson
229243730Srwatson	return (0);
230243730Srwatson}
231243730Srwatson
232243730Srwatsonstatic int
233243730Srwatsonuds_send(void *ctx, const unsigned char *data, size_t size, int fd)
234243730Srwatson{
235243730Srwatson	struct uds_ctx *uctx = ctx;
236243730Srwatson
237243730Srwatson	PJDLOG_ASSERT(uctx != NULL);
238243730Srwatson	PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
239243730Srwatson	PJDLOG_ASSERT(uctx->uc_fd >= 0);
240243730Srwatson
241243730Srwatson	return (proto_common_send(uctx->uc_fd, data, size, fd));
242243730Srwatson}
243243730Srwatson
244243730Srwatsonstatic int
245243730Srwatsonuds_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
246243730Srwatson{
247243730Srwatson	struct uds_ctx *uctx = ctx;
248243730Srwatson
249243730Srwatson	PJDLOG_ASSERT(uctx != NULL);
250243730Srwatson	PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
251243730Srwatson	PJDLOG_ASSERT(uctx->uc_fd >= 0);
252243730Srwatson
253243730Srwatson	return (proto_common_recv(uctx->uc_fd, data, size, fdp));
254243730Srwatson}
255243730Srwatson
256243730Srwatsonstatic int
257243730Srwatsonuds_descriptor(const void *ctx)
258243730Srwatson{
259243730Srwatson	const struct uds_ctx *uctx = ctx;
260243730Srwatson
261243730Srwatson	PJDLOG_ASSERT(uctx != NULL);
262243730Srwatson	PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
263243730Srwatson
264243730Srwatson	return (uctx->uc_fd);
265243730Srwatson}
266243730Srwatson
267243730Srwatsonstatic void
268243730Srwatsonuds_local_address(const void *ctx, char *addr, size_t size)
269243730Srwatson{
270243730Srwatson	const struct uds_ctx *uctx = ctx;
271243730Srwatson	struct sockaddr_un sun;
272243730Srwatson	socklen_t sunlen;
273243730Srwatson
274243730Srwatson	PJDLOG_ASSERT(uctx != NULL);
275243730Srwatson	PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
276243730Srwatson	PJDLOG_ASSERT(addr != NULL);
277243730Srwatson
278243730Srwatson	sunlen = sizeof(sun);
279243730Srwatson	if (getsockname(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) < 0) {
280243730Srwatson		PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
281243730Srwatson		return;
282243730Srwatson	}
283243730Srwatson	PJDLOG_ASSERT(sun.sun_family == AF_UNIX);
284243730Srwatson	if (sun.sun_path[0] == '\0') {
285243730Srwatson		PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
286243730Srwatson		return;
287243730Srwatson	}
288243730Srwatson	PJDLOG_VERIFY(snprintf(addr, size, "uds://%s", sun.sun_path) < (ssize_t)size);
289243730Srwatson}
290243730Srwatson
291243730Srwatsonstatic void
292243730Srwatsonuds_remote_address(const void *ctx, char *addr, size_t size)
293243730Srwatson{
294243730Srwatson	const struct uds_ctx *uctx = ctx;
295243730Srwatson	struct sockaddr_un sun;
296243730Srwatson	socklen_t sunlen;
297243730Srwatson
298243730Srwatson	PJDLOG_ASSERT(uctx != NULL);
299243730Srwatson	PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
300243730Srwatson	PJDLOG_ASSERT(addr != NULL);
301243730Srwatson
302243730Srwatson	sunlen = sizeof(sun);
303243730Srwatson	if (getpeername(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) < 0) {
304243730Srwatson		PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
305243730Srwatson		return;
306243730Srwatson	}
307243730Srwatson	PJDLOG_ASSERT(sun.sun_family == AF_UNIX);
308243730Srwatson	if (sun.sun_path[0] == '\0') {
309243730Srwatson		PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
310243730Srwatson		return;
311243730Srwatson	}
312243730Srwatson	snprintf(addr, size, "uds://%s", sun.sun_path);
313243730Srwatson}
314243730Srwatson
315243730Srwatsonstatic void
316243730Srwatsonuds_close(void *ctx)
317243730Srwatson{
318243730Srwatson	struct uds_ctx *uctx = ctx;
319243730Srwatson
320243730Srwatson	PJDLOG_ASSERT(uctx != NULL);
321243730Srwatson	PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
322243730Srwatson
323243730Srwatson	if (uctx->uc_fd >= 0)
324243730Srwatson		close(uctx->uc_fd);
325243730Srwatson	/*
326243730Srwatson	 * Unlink the socket only if we are the owner and this is descriptor
327243730Srwatson	 * we listen on.
328243730Srwatson	 */
329243730Srwatson	if (uctx->uc_side == UDS_SIDE_SERVER_LISTEN &&
330243730Srwatson	    uctx->uc_owner == getpid()) {
331243730Srwatson		PJDLOG_ASSERT(uctx->uc_sun.sun_path[0] != '\0');
332243730Srwatson		if (unlink(uctx->uc_sun.sun_path) == -1) {
333243730Srwatson			pjdlog_errno(LOG_WARNING,
334243730Srwatson			    "Unable to unlink socket file %s",
335243730Srwatson			    uctx->uc_sun.sun_path);
336243730Srwatson		}
337243730Srwatson	}
338243730Srwatson	uctx->uc_owner = 0;
339243730Srwatson	uctx->uc_magic = 0;
340243730Srwatson	free(uctx);
341243730Srwatson}
342243730Srwatson
343243730Srwatsonstatic struct proto uds_proto = {
344243730Srwatson	.prt_name = "uds",
345243730Srwatson	.prt_connect = uds_connect,
346243730Srwatson	.prt_connect_wait = uds_connect_wait,
347243730Srwatson	.prt_server = uds_server,
348243730Srwatson	.prt_accept = uds_accept,
349243730Srwatson	.prt_send = uds_send,
350243730Srwatson	.prt_recv = uds_recv,
351243730Srwatson	.prt_descriptor = uds_descriptor,
352243730Srwatson	.prt_local_address = uds_local_address,
353243730Srwatson	.prt_remote_address = uds_remote_address,
354243730Srwatson	.prt_close = uds_close
355243730Srwatson};
356243730Srwatson
357243730Srwatsonstatic __constructor void
358243730Srwatsonuds_ctor(void)
359243730Srwatson{
360243730Srwatson
361243730Srwatson	proto_register(&uds_proto, false);
362243730Srwatson}
363