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 * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/proto_uds.c#2 $ 30 */ 31 32 /* UDS - UNIX Domain Socket */ 33 34 #include <config/config.h> 35 36 #include <sys/types.h> 37 #include <sys/socket.h> 38 #include <sys/un.h> 39 40 #include <errno.h> 41 #include <stdbool.h> 42 #include <stdint.h> 43 #include <stdio.h> 44 #include <string.h> 45 #include <unistd.h> 46 47 #ifndef HAVE_STRLCPY 48 #include <compat/strlcpy.h> 49 #endif 50 51 #include "pjdlog.h" 52 #include "proto_impl.h" 53 54 #define UDS_CTX_MAGIC 0xd541c 55 struct uds_ctx { 56 int uc_magic; 57 struct sockaddr_un uc_sun; 58 int uc_fd; 59 int uc_side; 60 #define UDS_SIDE_CLIENT 0 61 #define UDS_SIDE_SERVER_LISTEN 1 62 #define UDS_SIDE_SERVER_WORK 2 63 pid_t uc_owner; 64 }; 65 66 static void uds_close(void *ctx); 67 68 static int 69 uds_addr(const char *addr, struct sockaddr_un *sunp) 70 { 71 72 if (addr == NULL) 73 return (-1); 74 75 if (strncasecmp(addr, "uds://", 6) == 0) 76 addr += 6; 77 else if (strncasecmp(addr, "unix://", 7) == 0) 78 addr += 7; 79 else if (addr[0] == '/' && /* If it starts from /... */ 80 strstr(addr, "://") == NULL)/* ...and there is no prefix... */ 81 ; /* ...we assume its us. */ 82 else 83 return (-1); 84 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); 89 } 90 #ifdef HAVE_SOCKADDR_STORAGE_SS_LEN 91 sunp->sun_len = SUN_LEN(sunp); 92 #endif 93 94 return (0); 95 } 96 97 static int 98 uds_common_setup(const char *addr, int side, struct uds_ctx **uctxp) 99 { 100 struct uds_ctx *uctx; 101 int error; 102 103 uctx = malloc(sizeof(*uctx)); 104 if (uctx == NULL) 105 return (errno); 106 107 /* Parse given address. */ 108 error = uds_addr(addr, &uctx->uc_sun); 109 if (error != 0) { 110 free(uctx); 111 return (error); 112 } 113 114 uctx->uc_fd = socket(AF_UNIX, SOCK_STREAM, 0); 115 if (uctx->uc_fd == -1) { 116 error = errno; 117 free(uctx); 118 return (error); 119 } 120 121 uctx->uc_side = side; 122 uctx->uc_owner = 0; 123 uctx->uc_magic = UDS_CTX_MAGIC; 124 *uctxp = uctx; 125 126 return (0); 127 } 128 129 static int 130 uds_connect(const char *srcaddr, const char *dstaddr, int timeout, void **ctxp) 131 { 132 struct uds_ctx *uctx; 133 int error; 134 135 PJDLOG_ASSERT(dstaddr != NULL); 136 PJDLOG_ASSERT(timeout >= -1); 137 138 error = uds_common_setup(dstaddr, UDS_SIDE_CLIENT, &uctx); 139 if (error != 0) 140 return (error); 141 142 PJDLOG_ASSERT(srcaddr == NULL); 143 144 if (connect(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun, 145 sizeof(uctx->uc_sun)) == -1) { 146 error = errno; 147 uds_close(uctx); 148 return (error); 149 } 150 151 *ctxp = uctx; 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 error; 175 176 error = uds_common_setup(addr, UDS_SIDE_SERVER_LISTEN, &uctx); 177 if (error != 0) 178 return (error); 179 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) { 183 error = errno; 184 uds_close(uctx); 185 return (error); 186 } 187 uctx->uc_owner = getpid(); 188 if (listen(uctx->uc_fd, 8) == -1) { 189 error = errno; 190 uds_close(uctx); 191 return (error); 192 } 193 194 *ctxp = uctx; 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 error; 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 < 0) { 220 error = errno; 221 free(newuctx); 222 return (error); 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) < 0) { 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) < 0) { 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_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 355 }; 356 357 static __constructor void 358 uds_ctor(void) 359 { 360 361 proto_register(&uds_proto, false); 362 } 363