1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2009-2010 The FreeBSD Foundation 5 * All rights reserved. 6 * 7 * This software was developed by Pawel Jakub Dawidek under sponsorship from 8 * the FreeBSD Foundation. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> 33 __FBSDID("$FreeBSD$"); 34 35 /* UDS - UNIX Domain Socket */ 36 37 #include <sys/types.h> 38 #include <sys/socket.h> 39 #include <sys/un.h> 40 41 #include <errno.h> 42 #include <stdbool.h> 43 #include <stdint.h> 44 #include <stdio.h> 45 #include <string.h> 46 #include <unistd.h> 47 48 #include "pjdlog.h" 49 #include "proto_impl.h" 50 51 #define UDS_CTX_MAGIC 0xd541c 52 struct uds_ctx { 53 int uc_magic; 54 struct sockaddr_un uc_sun; 55 int uc_fd; 56 int uc_side; 57 #define UDS_SIDE_CLIENT 0 58 #define UDS_SIDE_SERVER_LISTEN 1 59 #define UDS_SIDE_SERVER_WORK 2 60 pid_t uc_owner; 61 }; 62 63 static void uds_close(void *ctx); 64 65 static int 66 uds_addr(const char *addr, struct sockaddr_un *sunp) 67 { 68 69 if (addr == NULL) 70 return (-1); 71 72 if (strncasecmp(addr, "uds://", 6) == 0) 73 addr += 6; 74 else if (strncasecmp(addr, "unix://", 7) == 0) 75 addr += 7; 76 else if (addr[0] == '/' && /* If it starts from /... */ 77 strstr(addr, "://") == NULL)/* ...and there is no prefix... */ 78 ; /* ...we assume its us. */ 79 else 80 return (-1); 81 82 sunp->sun_family = AF_UNIX; 83 if (strlcpy(sunp->sun_path, addr, sizeof(sunp->sun_path)) >= 84 sizeof(sunp->sun_path)) { 85 return (ENAMETOOLONG); 86 } 87 sunp->sun_len = SUN_LEN(sunp); 88 89 return (0); 90 } 91 92 static int 93 uds_common_setup(const char *addr, void **ctxp, int side) 94 { 95 struct uds_ctx *uctx; 96 int ret; 97 98 uctx = malloc(sizeof(*uctx)); 99 if (uctx == NULL) 100 return (errno); 101 102 /* Parse given address. */ 103 if ((ret = uds_addr(addr, &uctx->uc_sun)) != 0) { 104 free(uctx); 105 return (ret); 106 } 107 108 uctx->uc_fd = socket(AF_UNIX, SOCK_STREAM, 0); 109 if (uctx->uc_fd == -1) { 110 ret = errno; 111 free(uctx); 112 return (ret); 113 } 114 115 uctx->uc_side = side; 116 uctx->uc_owner = 0; 117 uctx->uc_magic = UDS_CTX_MAGIC; 118 *ctxp = uctx; 119 120 return (0); 121 } 122 123 static int 124 uds_client(const char *srcaddr, const char *dstaddr, void **ctxp) 125 { 126 int ret; 127 128 ret = uds_common_setup(dstaddr, ctxp, UDS_SIDE_CLIENT); 129 if (ret != 0) 130 return (ret); 131 132 PJDLOG_ASSERT(srcaddr == NULL); 133 134 return (0); 135 } 136 137 static int 138 uds_connect(void *ctx, int timeout) 139 { 140 struct uds_ctx *uctx = ctx; 141 142 PJDLOG_ASSERT(uctx != NULL); 143 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 144 PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT); 145 PJDLOG_ASSERT(uctx->uc_fd >= 0); 146 PJDLOG_ASSERT(timeout >= -1); 147 148 if (connect(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun, 149 sizeof(uctx->uc_sun)) == -1) { 150 return (errno); 151 } 152 153 return (0); 154 } 155 156 static int 157 uds_connect_wait(void *ctx, int timeout) 158 { 159 struct uds_ctx *uctx = ctx; 160 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); 166 167 return (0); 168 } 169 170 static int 171 uds_server(const char *addr, void **ctxp) 172 { 173 struct uds_ctx *uctx; 174 int ret; 175 176 ret = uds_common_setup(addr, ctxp, UDS_SIDE_SERVER_LISTEN); 177 if (ret != 0) 178 return (ret); 179 180 uctx = *ctxp; 181 182 (void)unlink(uctx->uc_sun.sun_path); 183 if (bind(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun, 184 sizeof(uctx->uc_sun)) == -1) { 185 ret = errno; 186 uds_close(uctx); 187 return (ret); 188 } 189 uctx->uc_owner = getpid(); 190 if (listen(uctx->uc_fd, 8) == -1) { 191 ret = errno; 192 uds_close(uctx); 193 return (ret); 194 } 195 196 return (0); 197 } 198 199 static int 200 uds_accept(void *ctx, void **newctxp) 201 { 202 struct uds_ctx *uctx = ctx; 203 struct uds_ctx *newuctx; 204 socklen_t fromlen; 205 int ret; 206 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); 211 212 newuctx = malloc(sizeof(*newuctx)); 213 if (newuctx == NULL) 214 return (errno); 215 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 == -1) { 220 ret = errno; 221 free(newuctx); 222 return (ret); 223 } 224 225 newuctx->uc_side = UDS_SIDE_SERVER_WORK; 226 newuctx->uc_magic = UDS_CTX_MAGIC; 227 *newctxp = newuctx; 228 229 return (0); 230 } 231 232 static int 233 uds_send(void *ctx, const unsigned char *data, size_t size, int fd) 234 { 235 struct uds_ctx *uctx = ctx; 236 237 PJDLOG_ASSERT(uctx != NULL); 238 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 239 PJDLOG_ASSERT(uctx->uc_fd >= 0); 240 241 return (proto_common_send(uctx->uc_fd, data, size, fd)); 242 } 243 244 static int 245 uds_recv(void *ctx, unsigned char *data, size_t size, int *fdp) 246 { 247 struct uds_ctx *uctx = ctx; 248 249 PJDLOG_ASSERT(uctx != NULL); 250 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 251 PJDLOG_ASSERT(uctx->uc_fd >= 0); 252 253 return (proto_common_recv(uctx->uc_fd, data, size, fdp)); 254 } 255 256 static int 257 uds_descriptor(const void *ctx) 258 { 259 const struct uds_ctx *uctx = ctx; 260 261 PJDLOG_ASSERT(uctx != NULL); 262 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 263 264 return (uctx->uc_fd); 265 } 266 267 static void 268 uds_local_address(const void *ctx, char *addr, size_t size) 269 { 270 const struct uds_ctx *uctx = ctx; 271 struct sockaddr_un sun; 272 socklen_t sunlen; 273 274 PJDLOG_ASSERT(uctx != NULL); 275 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 276 PJDLOG_ASSERT(addr != NULL); 277 278 sunlen = sizeof(sun); 279 if (getsockname(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) == -1) { 280 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 281 return; 282 } 283 PJDLOG_ASSERT(sun.sun_family == AF_UNIX); 284 if (sun.sun_path[0] == '\0') { 285 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 286 return; 287 } 288 PJDLOG_VERIFY(snprintf(addr, size, "uds://%s", sun.sun_path) < (ssize_t)size); 289 } 290 291 static void 292 uds_remote_address(const void *ctx, char *addr, size_t size) 293 { 294 const struct uds_ctx *uctx = ctx; 295 struct sockaddr_un sun; 296 socklen_t sunlen; 297 298 PJDLOG_ASSERT(uctx != NULL); 299 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 300 PJDLOG_ASSERT(addr != NULL); 301 302 sunlen = sizeof(sun); 303 if (getpeername(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) == -1) { 304 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 305 return; 306 } 307 PJDLOG_ASSERT(sun.sun_family == AF_UNIX); 308 if (sun.sun_path[0] == '\0') { 309 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 310 return; 311 } 312 snprintf(addr, size, "uds://%s", sun.sun_path); 313 } 314 315 static void 316 uds_close(void *ctx) 317 { 318 struct uds_ctx *uctx = ctx; 319 320 PJDLOG_ASSERT(uctx != NULL); 321 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 322 323 if (uctx->uc_fd >= 0) 324 close(uctx->uc_fd); 325 /* 326 * Unlink the socket only if we are the owner and this is descriptor 327 * we listen on. 328 */ 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); 336 } 337 } 338 uctx->uc_owner = 0; 339 uctx->uc_magic = 0; 340 free(uctx); 341 } 342 343 static struct proto uds_proto = { 344 .prt_name = "uds", 345 .prt_client = uds_client, 346 .prt_connect = uds_connect, 347 .prt_connect_wait = uds_connect_wait, 348 .prt_server = uds_server, 349 .prt_accept = uds_accept, 350 .prt_send = uds_send, 351 .prt_recv = uds_recv, 352 .prt_descriptor = uds_descriptor, 353 .prt_local_address = uds_local_address, 354 .prt_remote_address = uds_remote_address, 355 .prt_close = uds_close 356 }; 357 358 static __constructor void 359 uds_ctor(void) 360 { 361 362 proto_register(&uds_proto, false); 363 } 364