2 * Copyright (c) 2009-2010 The FreeBSD Foundation
5 * This software was developed by Pawel Jakub Dawidek under sponsorship from
6 * the FreeBSD Foundation.
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
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.
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
29 * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/proto_uds.c#2 $
32 /* UDS - UNIX Domain Socket */
34 #include <config/config.h>
36 #include <sys/types.h>
37 #include <sys/socket.h>
48 #include <compat/strlcpy.h>
52 #include "proto_impl.h"
54 #define UDS_CTX_MAGIC 0xd541c
57 struct sockaddr_un uc_sun;
60 #define UDS_SIDE_CLIENT 0
61 #define UDS_SIDE_SERVER_LISTEN 1
62 #define UDS_SIDE_SERVER_WORK 2
66 static void uds_close(void *ctx);
69 uds_addr(const char *addr, struct sockaddr_un *sunp)
75 if (strncasecmp(addr, "uds://", 6) == 0)
77 else if (strncasecmp(addr, "unix://", 7) == 0)
79 else if (addr[0] == '/' && /* If it starts from /... */
80 strstr(addr, "://") == NULL)/* ...and there is no prefix... */
81 ; /* ...we assume its us. */
85 sunp->sun_family = AF_UNIX;
86 if (strlcpy(sunp->sun_path, addr, sizeof(sunp->sun_path)) >=
87 sizeof(sunp->sun_path)) {
88 return (ENAMETOOLONG);
90 #ifdef HAVE_SOCKADDR_STORAGE_SS_LEN
91 sunp->sun_len = SUN_LEN(sunp);
98 uds_common_setup(const char *addr, int side, struct uds_ctx **uctxp)
100 struct uds_ctx *uctx;
103 uctx = malloc(sizeof(*uctx));
107 /* Parse given address. */
108 error = uds_addr(addr, &uctx->uc_sun);
114 uctx->uc_fd = socket(AF_UNIX, SOCK_STREAM, 0);
115 if (uctx->uc_fd == -1) {
121 uctx->uc_side = side;
123 uctx->uc_magic = UDS_CTX_MAGIC;
130 uds_connect(const char *srcaddr, const char *dstaddr, int timeout, void **ctxp)
132 struct uds_ctx *uctx;
135 PJDLOG_ASSERT(dstaddr != NULL);
136 PJDLOG_ASSERT(timeout >= -1);
138 error = uds_common_setup(dstaddr, UDS_SIDE_CLIENT, &uctx);
142 PJDLOG_ASSERT(srcaddr == NULL);
144 if (connect(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
145 sizeof(uctx->uc_sun)) == -1) {
157 uds_connect_wait(void *ctx, int timeout)
159 struct uds_ctx *uctx = ctx;
161 PJDLOG_ASSERT(uctx != NULL);
162 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
163 PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT);
164 PJDLOG_ASSERT(uctx->uc_fd >= 0);
165 PJDLOG_ASSERT(timeout >= 0);
171 uds_server(const char *addr, void **ctxp)
173 struct uds_ctx *uctx;
176 error = uds_common_setup(addr, UDS_SIDE_SERVER_LISTEN, &uctx);
180 (void)unlink(uctx->uc_sun.sun_path);
181 if (bind(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun,
182 sizeof(uctx->uc_sun)) == -1) {
187 uctx->uc_owner = getpid();
188 if (listen(uctx->uc_fd, 8) == -1) {
200 uds_accept(void *ctx, void **newctxp)
202 struct uds_ctx *uctx = ctx;
203 struct uds_ctx *newuctx;
207 PJDLOG_ASSERT(uctx != NULL);
208 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
209 PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_SERVER_LISTEN);
210 PJDLOG_ASSERT(uctx->uc_fd >= 0);
212 newuctx = malloc(sizeof(*newuctx));
216 fromlen = sizeof(newuctx->uc_sun);
217 newuctx->uc_fd = accept(uctx->uc_fd,
218 (struct sockaddr *)&newuctx->uc_sun, &fromlen);
219 if (newuctx->uc_fd < 0) {
225 newuctx->uc_side = UDS_SIDE_SERVER_WORK;
226 newuctx->uc_magic = UDS_CTX_MAGIC;
233 uds_send(void *ctx, const unsigned char *data, size_t size, int fd)
235 struct uds_ctx *uctx = ctx;
237 PJDLOG_ASSERT(uctx != NULL);
238 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
239 PJDLOG_ASSERT(uctx->uc_fd >= 0);
241 return (proto_common_send(uctx->uc_fd, data, size, fd));
245 uds_recv(void *ctx, unsigned char *data, size_t size, int *fdp)
247 struct uds_ctx *uctx = ctx;
249 PJDLOG_ASSERT(uctx != NULL);
250 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
251 PJDLOG_ASSERT(uctx->uc_fd >= 0);
253 return (proto_common_recv(uctx->uc_fd, data, size, fdp));
257 uds_descriptor(const void *ctx)
259 const struct uds_ctx *uctx = ctx;
261 PJDLOG_ASSERT(uctx != NULL);
262 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
264 return (uctx->uc_fd);
268 uds_local_address(const void *ctx, char *addr, size_t size)
270 const struct uds_ctx *uctx = ctx;
271 struct sockaddr_un sun;
274 PJDLOG_ASSERT(uctx != NULL);
275 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
276 PJDLOG_ASSERT(addr != NULL);
278 sunlen = sizeof(sun);
279 if (getsockname(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) < 0) {
280 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
283 PJDLOG_ASSERT(sun.sun_family == AF_UNIX);
284 if (sun.sun_path[0] == '\0') {
285 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
288 PJDLOG_VERIFY(snprintf(addr, size, "uds://%s", sun.sun_path) < (ssize_t)size);
292 uds_remote_address(const void *ctx, char *addr, size_t size)
294 const struct uds_ctx *uctx = ctx;
295 struct sockaddr_un sun;
298 PJDLOG_ASSERT(uctx != NULL);
299 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
300 PJDLOG_ASSERT(addr != NULL);
302 sunlen = sizeof(sun);
303 if (getpeername(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) < 0) {
304 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
307 PJDLOG_ASSERT(sun.sun_family == AF_UNIX);
308 if (sun.sun_path[0] == '\0') {
309 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size);
312 snprintf(addr, size, "uds://%s", sun.sun_path);
318 struct uds_ctx *uctx = ctx;
320 PJDLOG_ASSERT(uctx != NULL);
321 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC);
323 if (uctx->uc_fd >= 0)
326 * Unlink the socket only if we are the owner and this is descriptor
329 if (uctx->uc_side == UDS_SIDE_SERVER_LISTEN &&
330 uctx->uc_owner == getpid()) {
331 PJDLOG_ASSERT(uctx->uc_sun.sun_path[0] != '\0');
332 if (unlink(uctx->uc_sun.sun_path) == -1) {
333 pjdlog_errno(LOG_WARNING,
334 "Unable to unlink socket file %s",
335 uctx->uc_sun.sun_path);
343 static struct proto uds_proto = {
345 .prt_connect = uds_connect,
346 .prt_connect_wait = uds_connect_wait,
347 .prt_server = uds_server,
348 .prt_accept = uds_accept,
349 .prt_send = uds_send,
350 .prt_recv = uds_recv,
351 .prt_descriptor = uds_descriptor,
352 .prt_local_address = uds_local_address,
353 .prt_remote_address = uds_remote_address,
354 .prt_close = uds_close
357 static __constructor void
361 proto_register(&uds_proto, false);