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