1243730Srwatson/*- 2243730Srwatson * Copyright (c) 2009-2010 The FreeBSD Foundation 3243730Srwatson * All rights reserved. 4243730Srwatson * 5243730Srwatson * This software was developed by Pawel Jakub Dawidek under sponsorship from 6243730Srwatson * the FreeBSD Foundation. 7243730Srwatson * 8243730Srwatson * Redistribution and use in source and binary forms, with or without 9243730Srwatson * modification, are permitted provided that the following conditions 10243730Srwatson * are met: 11243730Srwatson * 1. Redistributions of source code must retain the above copyright 12243730Srwatson * notice, this list of conditions and the following disclaimer. 13243730Srwatson * 2. Redistributions in binary form must reproduce the above copyright 14243730Srwatson * notice, this list of conditions and the following disclaimer in the 15243730Srwatson * documentation and/or other materials provided with the distribution. 16243730Srwatson * 17243730Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 18243730Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19243730Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20243730Srwatson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 21243730Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22243730Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23243730Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24243730Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25243730Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26243730Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27243730Srwatson * SUCH DAMAGE. 28243730Srwatson * 29243734Srwatson * $P4: //depot/projects/trustedbsd/openbsm/bin/auditdistd/proto_uds.c#2 $ 30243730Srwatson */ 31243730Srwatson 32243730Srwatson/* UDS - UNIX Domain Socket */ 33243730Srwatson 34243734Srwatson#include <config/config.h> 35243730Srwatson 36243730Srwatson#include <sys/types.h> 37243730Srwatson#include <sys/socket.h> 38243730Srwatson#include <sys/un.h> 39243730Srwatson 40243730Srwatson#include <errno.h> 41243730Srwatson#include <stdbool.h> 42243730Srwatson#include <stdint.h> 43243730Srwatson#include <stdio.h> 44243730Srwatson#include <string.h> 45243730Srwatson#include <unistd.h> 46243730Srwatson 47243730Srwatson#ifndef HAVE_STRLCPY 48243730Srwatson#include <compat/strlcpy.h> 49243730Srwatson#endif 50243730Srwatson 51243730Srwatson#include "pjdlog.h" 52243730Srwatson#include "proto_impl.h" 53243730Srwatson 54243730Srwatson#define UDS_CTX_MAGIC 0xd541c 55243730Srwatsonstruct uds_ctx { 56243730Srwatson int uc_magic; 57243730Srwatson struct sockaddr_un uc_sun; 58243730Srwatson int uc_fd; 59243730Srwatson int uc_side; 60243730Srwatson#define UDS_SIDE_CLIENT 0 61243730Srwatson#define UDS_SIDE_SERVER_LISTEN 1 62243730Srwatson#define UDS_SIDE_SERVER_WORK 2 63243730Srwatson pid_t uc_owner; 64243730Srwatson}; 65243730Srwatson 66243730Srwatsonstatic void uds_close(void *ctx); 67243730Srwatson 68243730Srwatsonstatic int 69243730Srwatsonuds_addr(const char *addr, struct sockaddr_un *sunp) 70243730Srwatson{ 71243730Srwatson 72243730Srwatson if (addr == NULL) 73243730Srwatson return (-1); 74243730Srwatson 75243730Srwatson if (strncasecmp(addr, "uds://", 6) == 0) 76243730Srwatson addr += 6; 77243730Srwatson else if (strncasecmp(addr, "unix://", 7) == 0) 78243730Srwatson addr += 7; 79243730Srwatson else if (addr[0] == '/' && /* If it starts from /... */ 80243730Srwatson strstr(addr, "://") == NULL)/* ...and there is no prefix... */ 81243730Srwatson ; /* ...we assume its us. */ 82243730Srwatson else 83243730Srwatson return (-1); 84243730Srwatson 85243730Srwatson sunp->sun_family = AF_UNIX; 86243730Srwatson if (strlcpy(sunp->sun_path, addr, sizeof(sunp->sun_path)) >= 87243730Srwatson sizeof(sunp->sun_path)) { 88243730Srwatson return (ENAMETOOLONG); 89243730Srwatson } 90243730Srwatson#ifdef HAVE_SOCKADDR_STORAGE_SS_LEN 91243730Srwatson sunp->sun_len = SUN_LEN(sunp); 92243730Srwatson#endif 93243730Srwatson 94243730Srwatson return (0); 95243730Srwatson} 96243730Srwatson 97243730Srwatsonstatic int 98243730Srwatsonuds_common_setup(const char *addr, int side, struct uds_ctx **uctxp) 99243730Srwatson{ 100243730Srwatson struct uds_ctx *uctx; 101243730Srwatson int error; 102243730Srwatson 103243730Srwatson uctx = malloc(sizeof(*uctx)); 104243730Srwatson if (uctx == NULL) 105243730Srwatson return (errno); 106243730Srwatson 107243730Srwatson /* Parse given address. */ 108243730Srwatson error = uds_addr(addr, &uctx->uc_sun); 109243730Srwatson if (error != 0) { 110243730Srwatson free(uctx); 111243730Srwatson return (error); 112243730Srwatson } 113243730Srwatson 114243730Srwatson uctx->uc_fd = socket(AF_UNIX, SOCK_STREAM, 0); 115243730Srwatson if (uctx->uc_fd == -1) { 116243730Srwatson error = errno; 117243730Srwatson free(uctx); 118243730Srwatson return (error); 119243730Srwatson } 120243730Srwatson 121243730Srwatson uctx->uc_side = side; 122243730Srwatson uctx->uc_owner = 0; 123243730Srwatson uctx->uc_magic = UDS_CTX_MAGIC; 124243730Srwatson *uctxp = uctx; 125243730Srwatson 126243730Srwatson return (0); 127243730Srwatson} 128243730Srwatson 129243730Srwatsonstatic int 130243730Srwatsonuds_connect(const char *srcaddr, const char *dstaddr, int timeout, void **ctxp) 131243730Srwatson{ 132243730Srwatson struct uds_ctx *uctx; 133243730Srwatson int error; 134243730Srwatson 135243730Srwatson PJDLOG_ASSERT(dstaddr != NULL); 136243730Srwatson PJDLOG_ASSERT(timeout >= -1); 137243730Srwatson 138243730Srwatson error = uds_common_setup(dstaddr, UDS_SIDE_CLIENT, &uctx); 139243730Srwatson if (error != 0) 140243730Srwatson return (error); 141243730Srwatson 142243730Srwatson PJDLOG_ASSERT(srcaddr == NULL); 143243730Srwatson 144243730Srwatson if (connect(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun, 145243730Srwatson sizeof(uctx->uc_sun)) == -1) { 146243730Srwatson error = errno; 147243730Srwatson uds_close(uctx); 148243730Srwatson return (error); 149243730Srwatson } 150243730Srwatson 151243730Srwatson *ctxp = uctx; 152243730Srwatson 153243730Srwatson return (0); 154243730Srwatson} 155243730Srwatson 156243730Srwatsonstatic int 157243730Srwatsonuds_connect_wait(void *ctx, int timeout) 158243730Srwatson{ 159243730Srwatson struct uds_ctx *uctx = ctx; 160243730Srwatson 161243730Srwatson PJDLOG_ASSERT(uctx != NULL); 162243730Srwatson PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 163243730Srwatson PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT); 164243730Srwatson PJDLOG_ASSERT(uctx->uc_fd >= 0); 165243730Srwatson PJDLOG_ASSERT(timeout >= 0); 166243730Srwatson 167243730Srwatson return (0); 168243730Srwatson} 169243730Srwatson 170243730Srwatsonstatic int 171243730Srwatsonuds_server(const char *addr, void **ctxp) 172243730Srwatson{ 173243730Srwatson struct uds_ctx *uctx; 174243730Srwatson int error; 175243730Srwatson 176243730Srwatson error = uds_common_setup(addr, UDS_SIDE_SERVER_LISTEN, &uctx); 177243730Srwatson if (error != 0) 178243730Srwatson return (error); 179243730Srwatson 180243730Srwatson (void)unlink(uctx->uc_sun.sun_path); 181243730Srwatson if (bind(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun, 182243730Srwatson sizeof(uctx->uc_sun)) == -1) { 183243730Srwatson error = errno; 184243730Srwatson uds_close(uctx); 185243730Srwatson return (error); 186243730Srwatson } 187243730Srwatson uctx->uc_owner = getpid(); 188243730Srwatson if (listen(uctx->uc_fd, 8) == -1) { 189243730Srwatson error = errno; 190243730Srwatson uds_close(uctx); 191243730Srwatson return (error); 192243730Srwatson } 193243730Srwatson 194243730Srwatson *ctxp = uctx; 195243730Srwatson 196243730Srwatson return (0); 197243730Srwatson} 198243730Srwatson 199243730Srwatsonstatic int 200243730Srwatsonuds_accept(void *ctx, void **newctxp) 201243730Srwatson{ 202243730Srwatson struct uds_ctx *uctx = ctx; 203243730Srwatson struct uds_ctx *newuctx; 204243730Srwatson socklen_t fromlen; 205243730Srwatson int error; 206243730Srwatson 207243730Srwatson PJDLOG_ASSERT(uctx != NULL); 208243730Srwatson PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 209243730Srwatson PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_SERVER_LISTEN); 210243730Srwatson PJDLOG_ASSERT(uctx->uc_fd >= 0); 211243730Srwatson 212243730Srwatson newuctx = malloc(sizeof(*newuctx)); 213243730Srwatson if (newuctx == NULL) 214243730Srwatson return (errno); 215243730Srwatson 216243730Srwatson fromlen = sizeof(newuctx->uc_sun); 217243730Srwatson newuctx->uc_fd = accept(uctx->uc_fd, 218243730Srwatson (struct sockaddr *)&newuctx->uc_sun, &fromlen); 219243730Srwatson if (newuctx->uc_fd < 0) { 220243730Srwatson error = errno; 221243730Srwatson free(newuctx); 222243730Srwatson return (error); 223243730Srwatson } 224243730Srwatson 225243730Srwatson newuctx->uc_side = UDS_SIDE_SERVER_WORK; 226243730Srwatson newuctx->uc_magic = UDS_CTX_MAGIC; 227243730Srwatson *newctxp = newuctx; 228243730Srwatson 229243730Srwatson return (0); 230243730Srwatson} 231243730Srwatson 232243730Srwatsonstatic int 233243730Srwatsonuds_send(void *ctx, const unsigned char *data, size_t size, int fd) 234243730Srwatson{ 235243730Srwatson struct uds_ctx *uctx = ctx; 236243730Srwatson 237243730Srwatson PJDLOG_ASSERT(uctx != NULL); 238243730Srwatson PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 239243730Srwatson PJDLOG_ASSERT(uctx->uc_fd >= 0); 240243730Srwatson 241243730Srwatson return (proto_common_send(uctx->uc_fd, data, size, fd)); 242243730Srwatson} 243243730Srwatson 244243730Srwatsonstatic int 245243730Srwatsonuds_recv(void *ctx, unsigned char *data, size_t size, int *fdp) 246243730Srwatson{ 247243730Srwatson struct uds_ctx *uctx = ctx; 248243730Srwatson 249243730Srwatson PJDLOG_ASSERT(uctx != NULL); 250243730Srwatson PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 251243730Srwatson PJDLOG_ASSERT(uctx->uc_fd >= 0); 252243730Srwatson 253243730Srwatson return (proto_common_recv(uctx->uc_fd, data, size, fdp)); 254243730Srwatson} 255243730Srwatson 256243730Srwatsonstatic int 257243730Srwatsonuds_descriptor(const void *ctx) 258243730Srwatson{ 259243730Srwatson const struct uds_ctx *uctx = ctx; 260243730Srwatson 261243730Srwatson PJDLOG_ASSERT(uctx != NULL); 262243730Srwatson PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 263243730Srwatson 264243730Srwatson return (uctx->uc_fd); 265243730Srwatson} 266243730Srwatson 267243730Srwatsonstatic void 268243730Srwatsonuds_local_address(const void *ctx, char *addr, size_t size) 269243730Srwatson{ 270243730Srwatson const struct uds_ctx *uctx = ctx; 271243730Srwatson struct sockaddr_un sun; 272243730Srwatson socklen_t sunlen; 273243730Srwatson 274243730Srwatson PJDLOG_ASSERT(uctx != NULL); 275243730Srwatson PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 276243730Srwatson PJDLOG_ASSERT(addr != NULL); 277243730Srwatson 278243730Srwatson sunlen = sizeof(sun); 279243730Srwatson if (getsockname(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) < 0) { 280243730Srwatson PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 281243730Srwatson return; 282243730Srwatson } 283243730Srwatson PJDLOG_ASSERT(sun.sun_family == AF_UNIX); 284243730Srwatson if (sun.sun_path[0] == '\0') { 285243730Srwatson PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 286243730Srwatson return; 287243730Srwatson } 288243730Srwatson PJDLOG_VERIFY(snprintf(addr, size, "uds://%s", sun.sun_path) < (ssize_t)size); 289243730Srwatson} 290243730Srwatson 291243730Srwatsonstatic void 292243730Srwatsonuds_remote_address(const void *ctx, char *addr, size_t size) 293243730Srwatson{ 294243730Srwatson const struct uds_ctx *uctx = ctx; 295243730Srwatson struct sockaddr_un sun; 296243730Srwatson socklen_t sunlen; 297243730Srwatson 298243730Srwatson PJDLOG_ASSERT(uctx != NULL); 299243730Srwatson PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 300243730Srwatson PJDLOG_ASSERT(addr != NULL); 301243730Srwatson 302243730Srwatson sunlen = sizeof(sun); 303243730Srwatson if (getpeername(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) < 0) { 304243730Srwatson PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 305243730Srwatson return; 306243730Srwatson } 307243730Srwatson PJDLOG_ASSERT(sun.sun_family == AF_UNIX); 308243730Srwatson if (sun.sun_path[0] == '\0') { 309243730Srwatson PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 310243730Srwatson return; 311243730Srwatson } 312243730Srwatson snprintf(addr, size, "uds://%s", sun.sun_path); 313243730Srwatson} 314243730Srwatson 315243730Srwatsonstatic void 316243730Srwatsonuds_close(void *ctx) 317243730Srwatson{ 318243730Srwatson struct uds_ctx *uctx = ctx; 319243730Srwatson 320243730Srwatson PJDLOG_ASSERT(uctx != NULL); 321243730Srwatson PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 322243730Srwatson 323243730Srwatson if (uctx->uc_fd >= 0) 324243730Srwatson close(uctx->uc_fd); 325243730Srwatson /* 326243730Srwatson * Unlink the socket only if we are the owner and this is descriptor 327243730Srwatson * we listen on. 328243730Srwatson */ 329243730Srwatson if (uctx->uc_side == UDS_SIDE_SERVER_LISTEN && 330243730Srwatson uctx->uc_owner == getpid()) { 331243730Srwatson PJDLOG_ASSERT(uctx->uc_sun.sun_path[0] != '\0'); 332243730Srwatson if (unlink(uctx->uc_sun.sun_path) == -1) { 333243730Srwatson pjdlog_errno(LOG_WARNING, 334243730Srwatson "Unable to unlink socket file %s", 335243730Srwatson uctx->uc_sun.sun_path); 336243730Srwatson } 337243730Srwatson } 338243730Srwatson uctx->uc_owner = 0; 339243730Srwatson uctx->uc_magic = 0; 340243730Srwatson free(uctx); 341243730Srwatson} 342243730Srwatson 343243730Srwatsonstatic struct proto uds_proto = { 344243730Srwatson .prt_name = "uds", 345243730Srwatson .prt_connect = uds_connect, 346243730Srwatson .prt_connect_wait = uds_connect_wait, 347243730Srwatson .prt_server = uds_server, 348243730Srwatson .prt_accept = uds_accept, 349243730Srwatson .prt_send = uds_send, 350243730Srwatson .prt_recv = uds_recv, 351243730Srwatson .prt_descriptor = uds_descriptor, 352243730Srwatson .prt_local_address = uds_local_address, 353243730Srwatson .prt_remote_address = uds_remote_address, 354243730Srwatson .prt_close = uds_close 355243730Srwatson}; 356243730Srwatson 357243730Srwatsonstatic __constructor void 358243730Srwatsonuds_ctor(void) 359243730Srwatson{ 360243730Srwatson 361243730Srwatson proto_register(&uds_proto, false); 362243730Srwatson} 363