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