1 /*- 2 * Copyright (c) 2009-2010 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * This software was developed by Pawel Jakub Dawidek under sponsorship from 6 * the FreeBSD Foundation. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 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. 16 * 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 27 * SUCH DAMAGE. 28 */ 29 30 /* UDS - UNIX Domain Socket */ 31 32 #include <config/config.h> 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 #ifndef HAVE_STRLCPY 46 #include <compat/strlcpy.h> 47 #endif 48 49 #include "pjdlog.h" 50 #include "proto_impl.h" 51 52 #define UDS_CTX_MAGIC 0xd541c 53 struct uds_ctx { 54 int uc_magic; 55 struct sockaddr_un uc_sun; 56 int uc_fd; 57 int uc_side; 58 #define UDS_SIDE_CLIENT 0 59 #define UDS_SIDE_SERVER_LISTEN 1 60 #define UDS_SIDE_SERVER_WORK 2 61 pid_t uc_owner; 62 }; 63 64 static void uds_close(void *ctx); 65 66 static int 67 uds_addr(const char *addr, struct sockaddr_un *sunp) 68 { 69 70 if (addr == NULL) 71 return (-1); 72 73 if (strncasecmp(addr, "uds://", 6) == 0) 74 addr += 6; 75 else if (strncasecmp(addr, "unix://", 7) == 0) 76 addr += 7; 77 else if (addr[0] == '/' && /* If it starts from /... */ 78 strstr(addr, "://") == NULL)/* ...and there is no prefix... */ 79 ; /* ...we assume its us. */ 80 else 81 return (-1); 82 83 sunp->sun_family = AF_UNIX; 84 if (strlcpy(sunp->sun_path, addr, sizeof(sunp->sun_path)) >= 85 sizeof(sunp->sun_path)) { 86 return (ENAMETOOLONG); 87 } 88 #ifdef HAVE_SOCKADDR_STORAGE_SS_LEN 89 sunp->sun_len = SUN_LEN(sunp); 90 #endif 91 92 return (0); 93 } 94 95 static int 96 uds_common_setup(const char *addr, int side, struct uds_ctx **uctxp) 97 { 98 struct uds_ctx *uctx; 99 int error; 100 101 uctx = malloc(sizeof(*uctx)); 102 if (uctx == NULL) 103 return (errno); 104 105 /* Parse given address. */ 106 error = uds_addr(addr, &uctx->uc_sun); 107 if (error != 0) { 108 free(uctx); 109 return (error); 110 } 111 112 uctx->uc_fd = socket(AF_UNIX, SOCK_STREAM, 0); 113 if (uctx->uc_fd == -1) { 114 error = errno; 115 free(uctx); 116 return (error); 117 } 118 119 uctx->uc_side = side; 120 uctx->uc_owner = 0; 121 uctx->uc_magic = UDS_CTX_MAGIC; 122 *uctxp = uctx; 123 124 return (0); 125 } 126 127 static int 128 uds_connect(const char *srcaddr, const char *dstaddr, int timeout, void **ctxp) 129 { 130 struct uds_ctx *uctx; 131 int error; 132 133 PJDLOG_ASSERT(dstaddr != NULL); 134 PJDLOG_ASSERT(timeout >= -1); 135 136 error = uds_common_setup(dstaddr, UDS_SIDE_CLIENT, &uctx); 137 if (error != 0) 138 return (error); 139 140 PJDLOG_ASSERT(srcaddr == NULL); 141 142 if (connect(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun, 143 sizeof(uctx->uc_sun)) == -1) { 144 error = errno; 145 uds_close(uctx); 146 return (error); 147 } 148 149 *ctxp = uctx; 150 151 return (0); 152 } 153 154 static int 155 uds_connect_wait(void *ctx, int timeout) 156 { 157 struct uds_ctx *uctx = ctx; 158 159 PJDLOG_ASSERT(uctx != NULL); 160 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 161 PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT); 162 PJDLOG_ASSERT(uctx->uc_fd >= 0); 163 PJDLOG_ASSERT(timeout >= 0); 164 165 return (0); 166 } 167 168 static int 169 uds_server(const char *addr, void **ctxp) 170 { 171 struct uds_ctx *uctx; 172 int error; 173 174 error = uds_common_setup(addr, UDS_SIDE_SERVER_LISTEN, &uctx); 175 if (error != 0) 176 return (error); 177 178 (void)unlink(uctx->uc_sun.sun_path); 179 if (bind(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun, 180 sizeof(uctx->uc_sun)) == -1) { 181 error = errno; 182 uds_close(uctx); 183 return (error); 184 } 185 uctx->uc_owner = getpid(); 186 if (listen(uctx->uc_fd, 8) == -1) { 187 error = errno; 188 uds_close(uctx); 189 return (error); 190 } 191 192 *ctxp = uctx; 193 194 return (0); 195 } 196 197 static int 198 uds_accept(void *ctx, void **newctxp) 199 { 200 struct uds_ctx *uctx = ctx; 201 struct uds_ctx *newuctx; 202 socklen_t fromlen; 203 int error; 204 205 PJDLOG_ASSERT(uctx != NULL); 206 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 207 PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_SERVER_LISTEN); 208 PJDLOG_ASSERT(uctx->uc_fd >= 0); 209 210 newuctx = malloc(sizeof(*newuctx)); 211 if (newuctx == NULL) 212 return (errno); 213 214 fromlen = sizeof(newuctx->uc_sun); 215 newuctx->uc_fd = accept(uctx->uc_fd, 216 (struct sockaddr *)&newuctx->uc_sun, &fromlen); 217 if (newuctx->uc_fd < 0) { 218 error = errno; 219 free(newuctx); 220 return (error); 221 } 222 223 newuctx->uc_side = UDS_SIDE_SERVER_WORK; 224 newuctx->uc_magic = UDS_CTX_MAGIC; 225 *newctxp = newuctx; 226 227 return (0); 228 } 229 230 static int 231 uds_send(void *ctx, const unsigned char *data, size_t size, int fd) 232 { 233 struct uds_ctx *uctx = ctx; 234 235 PJDLOG_ASSERT(uctx != NULL); 236 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 237 PJDLOG_ASSERT(uctx->uc_fd >= 0); 238 239 return (proto_common_send(uctx->uc_fd, data, size, fd)); 240 } 241 242 static int 243 uds_recv(void *ctx, unsigned char *data, size_t size, int *fdp) 244 { 245 struct uds_ctx *uctx = ctx; 246 247 PJDLOG_ASSERT(uctx != NULL); 248 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 249 PJDLOG_ASSERT(uctx->uc_fd >= 0); 250 251 return (proto_common_recv(uctx->uc_fd, data, size, fdp)); 252 } 253 254 static int 255 uds_descriptor(const void *ctx) 256 { 257 const struct uds_ctx *uctx = ctx; 258 259 PJDLOG_ASSERT(uctx != NULL); 260 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 261 262 return (uctx->uc_fd); 263 } 264 265 static void 266 uds_local_address(const void *ctx, char *addr, size_t size) 267 { 268 const struct uds_ctx *uctx = ctx; 269 struct sockaddr_un sun; 270 socklen_t sunlen; 271 272 PJDLOG_ASSERT(uctx != NULL); 273 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 274 PJDLOG_ASSERT(addr != NULL); 275 276 sunlen = sizeof(sun); 277 if (getsockname(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) < 0) { 278 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 279 return; 280 } 281 PJDLOG_ASSERT(sun.sun_family == AF_UNIX); 282 if (sun.sun_path[0] == '\0') { 283 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 284 return; 285 } 286 PJDLOG_VERIFY(snprintf(addr, size, "uds://%s", sun.sun_path) < (ssize_t)size); 287 } 288 289 static void 290 uds_remote_address(const void *ctx, char *addr, size_t size) 291 { 292 const struct uds_ctx *uctx = ctx; 293 struct sockaddr_un sun; 294 socklen_t sunlen; 295 296 PJDLOG_ASSERT(uctx != NULL); 297 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 298 PJDLOG_ASSERT(addr != NULL); 299 300 sunlen = sizeof(sun); 301 if (getpeername(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) < 0) { 302 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 303 return; 304 } 305 PJDLOG_ASSERT(sun.sun_family == AF_UNIX); 306 if (sun.sun_path[0] == '\0') { 307 PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 308 return; 309 } 310 snprintf(addr, size, "uds://%s", sun.sun_path); 311 } 312 313 static void 314 uds_close(void *ctx) 315 { 316 struct uds_ctx *uctx = ctx; 317 318 PJDLOG_ASSERT(uctx != NULL); 319 PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 320 321 if (uctx->uc_fd >= 0) 322 close(uctx->uc_fd); 323 /* 324 * Unlink the socket only if we are the owner and this is descriptor 325 * we listen on. 326 */ 327 if (uctx->uc_side == UDS_SIDE_SERVER_LISTEN && 328 uctx->uc_owner == getpid()) { 329 PJDLOG_ASSERT(uctx->uc_sun.sun_path[0] != '\0'); 330 if (unlink(uctx->uc_sun.sun_path) == -1) { 331 pjdlog_errno(LOG_WARNING, 332 "Unable to unlink socket file %s", 333 uctx->uc_sun.sun_path); 334 } 335 } 336 uctx->uc_owner = 0; 337 uctx->uc_magic = 0; 338 free(uctx); 339 } 340 341 static struct proto uds_proto = { 342 .prt_name = "uds", 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