1204076Spjd/*- 2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330449Seadler * 4204076Spjd * Copyright (c) 2009-2010 The FreeBSD Foundation 5204076Spjd * All rights reserved. 6204076Spjd * 7204076Spjd * This software was developed by Pawel Jakub Dawidek under sponsorship from 8204076Spjd * the FreeBSD Foundation. 9204076Spjd * 10204076Spjd * Redistribution and use in source and binary forms, with or without 11204076Spjd * modification, are permitted provided that the following conditions 12204076Spjd * are met: 13204076Spjd * 1. Redistributions of source code must retain the above copyright 14204076Spjd * notice, this list of conditions and the following disclaimer. 15204076Spjd * 2. Redistributions in binary form must reproduce the above copyright 16204076Spjd * notice, this list of conditions and the following disclaimer in the 17204076Spjd * documentation and/or other materials provided with the distribution. 18204076Spjd * 19204076Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 20204076Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21204076Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22204076Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 23204076Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24204076Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25204076Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26204076Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27204076Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28204076Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29204076Spjd * SUCH DAMAGE. 30204076Spjd */ 31204076Spjd 32204076Spjd#include <sys/cdefs.h> 33204076Spjd__FBSDID("$FreeBSD: stable/11/sbin/hastd/proto_uds.c 330449 2018-03-05 07:26:05Z eadler $"); 34204076Spjd 35204076Spjd/* UDS - UNIX Domain Socket */ 36204076Spjd 37218465Spjd#include <sys/types.h> 38219873Spjd#include <sys/socket.h> 39204076Spjd#include <sys/un.h> 40204076Spjd 41204076Spjd#include <errno.h> 42204076Spjd#include <stdbool.h> 43204076Spjd#include <stdint.h> 44204076Spjd#include <stdio.h> 45204076Spjd#include <string.h> 46204076Spjd#include <unistd.h> 47204076Spjd 48210876Spjd#include "pjdlog.h" 49204076Spjd#include "proto_impl.h" 50204076Spjd 51204076Spjd#define UDS_CTX_MAGIC 0xd541c 52204076Spjdstruct uds_ctx { 53204076Spjd int uc_magic; 54204076Spjd struct sockaddr_un uc_sun; 55204076Spjd int uc_fd; 56204076Spjd int uc_side; 57204076Spjd#define UDS_SIDE_CLIENT 0 58204076Spjd#define UDS_SIDE_SERVER_LISTEN 1 59204076Spjd#define UDS_SIDE_SERVER_WORK 2 60218464Spjd pid_t uc_owner; 61204076Spjd}; 62204076Spjd 63204076Spjdstatic void uds_close(void *ctx); 64204076Spjd 65204076Spjdstatic int 66204076Spjduds_addr(const char *addr, struct sockaddr_un *sunp) 67204076Spjd{ 68204076Spjd 69204076Spjd if (addr == NULL) 70204076Spjd return (-1); 71204076Spjd 72204076Spjd if (strncasecmp(addr, "uds://", 6) == 0) 73204076Spjd addr += 6; 74204076Spjd else if (strncasecmp(addr, "unix://", 7) == 0) 75204076Spjd addr += 7; 76204076Spjd else if (addr[0] == '/' && /* If it starts from /... */ 77204076Spjd strstr(addr, "://") == NULL)/* ...and there is no prefix... */ 78204076Spjd ; /* ...we assume its us. */ 79204076Spjd else 80204076Spjd return (-1); 81204076Spjd 82204076Spjd sunp->sun_family = AF_UNIX; 83204076Spjd if (strlcpy(sunp->sun_path, addr, sizeof(sunp->sun_path)) >= 84204076Spjd sizeof(sunp->sun_path)) { 85204076Spjd return (ENAMETOOLONG); 86204076Spjd } 87204076Spjd sunp->sun_len = SUN_LEN(sunp); 88204076Spjd 89204076Spjd return (0); 90204076Spjd} 91204076Spjd 92204076Spjdstatic int 93204076Spjduds_common_setup(const char *addr, void **ctxp, int side) 94204076Spjd{ 95204076Spjd struct uds_ctx *uctx; 96204076Spjd int ret; 97204076Spjd 98204076Spjd uctx = malloc(sizeof(*uctx)); 99204076Spjd if (uctx == NULL) 100204076Spjd return (errno); 101204076Spjd 102204076Spjd /* Parse given address. */ 103204076Spjd if ((ret = uds_addr(addr, &uctx->uc_sun)) != 0) { 104204076Spjd free(uctx); 105204076Spjd return (ret); 106204076Spjd } 107204076Spjd 108204076Spjd uctx->uc_fd = socket(AF_UNIX, SOCK_STREAM, 0); 109204076Spjd if (uctx->uc_fd == -1) { 110204076Spjd ret = errno; 111204076Spjd free(uctx); 112204076Spjd return (ret); 113204076Spjd } 114204076Spjd 115204076Spjd uctx->uc_side = side; 116218464Spjd uctx->uc_owner = 0; 117204076Spjd uctx->uc_magic = UDS_CTX_MAGIC; 118204076Spjd *ctxp = uctx; 119204076Spjd 120204076Spjd return (0); 121204076Spjd} 122204076Spjd 123204076Spjdstatic int 124219818Spjduds_client(const char *srcaddr, const char *dstaddr, void **ctxp) 125204076Spjd{ 126219818Spjd int ret; 127204076Spjd 128219818Spjd ret = uds_common_setup(dstaddr, ctxp, UDS_SIDE_CLIENT); 129219818Spjd if (ret != 0) 130219818Spjd return (ret); 131219818Spjd 132219818Spjd PJDLOG_ASSERT(srcaddr == NULL); 133219818Spjd 134219818Spjd return (0); 135204076Spjd} 136204076Spjd 137204076Spjdstatic int 138218192Spjduds_connect(void *ctx, int timeout) 139204076Spjd{ 140204076Spjd struct uds_ctx *uctx = ctx; 141204076Spjd 142218138Spjd PJDLOG_ASSERT(uctx != NULL); 143218138Spjd PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 144218138Spjd PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT); 145218138Spjd PJDLOG_ASSERT(uctx->uc_fd >= 0); 146218193Spjd PJDLOG_ASSERT(timeout >= -1); 147204076Spjd 148204076Spjd if (connect(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun, 149229945Spjd sizeof(uctx->uc_sun)) == -1) { 150204076Spjd return (errno); 151204076Spjd } 152204076Spjd 153204076Spjd return (0); 154204076Spjd} 155204076Spjd 156204076Spjdstatic int 157218193Spjduds_connect_wait(void *ctx, int timeout) 158218193Spjd{ 159218193Spjd struct uds_ctx *uctx = ctx; 160218193Spjd 161218193Spjd PJDLOG_ASSERT(uctx != NULL); 162218193Spjd PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 163218193Spjd PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_CLIENT); 164218193Spjd PJDLOG_ASSERT(uctx->uc_fd >= 0); 165218193Spjd PJDLOG_ASSERT(timeout >= 0); 166218193Spjd 167218193Spjd return (0); 168218193Spjd} 169218193Spjd 170218193Spjdstatic int 171204076Spjduds_server(const char *addr, void **ctxp) 172204076Spjd{ 173204076Spjd struct uds_ctx *uctx; 174204076Spjd int ret; 175204076Spjd 176204076Spjd ret = uds_common_setup(addr, ctxp, UDS_SIDE_SERVER_LISTEN); 177204076Spjd if (ret != 0) 178204076Spjd return (ret); 179204076Spjd 180204076Spjd uctx = *ctxp; 181204076Spjd 182218464Spjd (void)unlink(uctx->uc_sun.sun_path); 183204076Spjd if (bind(uctx->uc_fd, (struct sockaddr *)&uctx->uc_sun, 184229945Spjd sizeof(uctx->uc_sun)) == -1) { 185204076Spjd ret = errno; 186204076Spjd uds_close(uctx); 187204076Spjd return (ret); 188204076Spjd } 189218464Spjd uctx->uc_owner = getpid(); 190229945Spjd if (listen(uctx->uc_fd, 8) == -1) { 191204076Spjd ret = errno; 192204076Spjd uds_close(uctx); 193204076Spjd return (ret); 194204076Spjd } 195204076Spjd 196204076Spjd return (0); 197204076Spjd} 198204076Spjd 199204076Spjdstatic int 200204076Spjduds_accept(void *ctx, void **newctxp) 201204076Spjd{ 202204076Spjd struct uds_ctx *uctx = ctx; 203204076Spjd struct uds_ctx *newuctx; 204204076Spjd socklen_t fromlen; 205204076Spjd int ret; 206204076Spjd 207218138Spjd PJDLOG_ASSERT(uctx != NULL); 208218138Spjd PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 209218138Spjd PJDLOG_ASSERT(uctx->uc_side == UDS_SIDE_SERVER_LISTEN); 210218138Spjd PJDLOG_ASSERT(uctx->uc_fd >= 0); 211204076Spjd 212204076Spjd newuctx = malloc(sizeof(*newuctx)); 213204076Spjd if (newuctx == NULL) 214204076Spjd return (errno); 215204076Spjd 216218464Spjd fromlen = sizeof(newuctx->uc_sun); 217218464Spjd newuctx->uc_fd = accept(uctx->uc_fd, 218218464Spjd (struct sockaddr *)&newuctx->uc_sun, &fromlen); 219229945Spjd if (newuctx->uc_fd == -1) { 220204076Spjd ret = errno; 221204076Spjd free(newuctx); 222204076Spjd return (ret); 223204076Spjd } 224204076Spjd 225204076Spjd newuctx->uc_side = UDS_SIDE_SERVER_WORK; 226204076Spjd newuctx->uc_magic = UDS_CTX_MAGIC; 227204076Spjd *newctxp = newuctx; 228204076Spjd 229204076Spjd return (0); 230204076Spjd} 231204076Spjd 232204076Spjdstatic int 233218194Spjduds_send(void *ctx, const unsigned char *data, size_t size, int fd) 234204076Spjd{ 235204076Spjd struct uds_ctx *uctx = ctx; 236204076Spjd 237218138Spjd PJDLOG_ASSERT(uctx != NULL); 238218138Spjd PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 239218138Spjd PJDLOG_ASSERT(uctx->uc_fd >= 0); 240204076Spjd 241218194Spjd return (proto_common_send(uctx->uc_fd, data, size, fd)); 242204076Spjd} 243204076Spjd 244204076Spjdstatic int 245218194Spjduds_recv(void *ctx, unsigned char *data, size_t size, int *fdp) 246204076Spjd{ 247204076Spjd struct uds_ctx *uctx = ctx; 248204076Spjd 249218138Spjd PJDLOG_ASSERT(uctx != NULL); 250218138Spjd PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 251218138Spjd PJDLOG_ASSERT(uctx->uc_fd >= 0); 252204076Spjd 253218194Spjd return (proto_common_recv(uctx->uc_fd, data, size, fdp)); 254204076Spjd} 255204076Spjd 256204076Spjdstatic int 257204076Spjduds_descriptor(const void *ctx) 258204076Spjd{ 259204076Spjd const struct uds_ctx *uctx = ctx; 260204076Spjd 261218138Spjd PJDLOG_ASSERT(uctx != NULL); 262218138Spjd PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 263204076Spjd 264204076Spjd return (uctx->uc_fd); 265204076Spjd} 266204076Spjd 267204076Spjdstatic void 268204076Spjduds_local_address(const void *ctx, char *addr, size_t size) 269204076Spjd{ 270204076Spjd const struct uds_ctx *uctx = ctx; 271204076Spjd struct sockaddr_un sun; 272204076Spjd socklen_t sunlen; 273204076Spjd 274218138Spjd PJDLOG_ASSERT(uctx != NULL); 275218138Spjd PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 276218138Spjd PJDLOG_ASSERT(addr != NULL); 277204076Spjd 278204076Spjd sunlen = sizeof(sun); 279229945Spjd if (getsockname(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) == -1) { 280210876Spjd PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 281204076Spjd return; 282204076Spjd } 283218138Spjd PJDLOG_ASSERT(sun.sun_family == AF_UNIX); 284204076Spjd if (sun.sun_path[0] == '\0') { 285210876Spjd PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 286204076Spjd return; 287204076Spjd } 288210876Spjd PJDLOG_VERIFY(snprintf(addr, size, "uds://%s", sun.sun_path) < (ssize_t)size); 289204076Spjd} 290204076Spjd 291204076Spjdstatic void 292204076Spjduds_remote_address(const void *ctx, char *addr, size_t size) 293204076Spjd{ 294204076Spjd const struct uds_ctx *uctx = ctx; 295204076Spjd struct sockaddr_un sun; 296204076Spjd socklen_t sunlen; 297204076Spjd 298218138Spjd PJDLOG_ASSERT(uctx != NULL); 299218138Spjd PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 300218138Spjd PJDLOG_ASSERT(addr != NULL); 301204076Spjd 302204076Spjd sunlen = sizeof(sun); 303229945Spjd if (getpeername(uctx->uc_fd, (struct sockaddr *)&sun, &sunlen) == -1) { 304210876Spjd PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 305204076Spjd return; 306204076Spjd } 307218138Spjd PJDLOG_ASSERT(sun.sun_family == AF_UNIX); 308204076Spjd if (sun.sun_path[0] == '\0') { 309210876Spjd PJDLOG_VERIFY(strlcpy(addr, "N/A", size) < size); 310204076Spjd return; 311204076Spjd } 312204076Spjd snprintf(addr, size, "uds://%s", sun.sun_path); 313204076Spjd} 314204076Spjd 315204076Spjdstatic void 316204076Spjduds_close(void *ctx) 317204076Spjd{ 318204076Spjd struct uds_ctx *uctx = ctx; 319204076Spjd 320218138Spjd PJDLOG_ASSERT(uctx != NULL); 321218138Spjd PJDLOG_ASSERT(uctx->uc_magic == UDS_CTX_MAGIC); 322204076Spjd 323204076Spjd if (uctx->uc_fd >= 0) 324204076Spjd close(uctx->uc_fd); 325218464Spjd /* 326218464Spjd * Unlink the socket only if we are the owner and this is descriptor 327218464Spjd * we listen on. 328218464Spjd */ 329218464Spjd if (uctx->uc_side == UDS_SIDE_SERVER_LISTEN && 330218464Spjd uctx->uc_owner == getpid()) { 331218474Spjd PJDLOG_ASSERT(uctx->uc_sun.sun_path[0] != '\0'); 332218474Spjd if (unlink(uctx->uc_sun.sun_path) == -1) { 333218474Spjd pjdlog_errno(LOG_WARNING, 334218474Spjd "Unable to unlink socket file %s", 335218474Spjd uctx->uc_sun.sun_path); 336218474Spjd } 337218464Spjd } 338218464Spjd uctx->uc_owner = 0; 339204076Spjd uctx->uc_magic = 0; 340204076Spjd free(uctx); 341204076Spjd} 342204076Spjd 343219873Spjdstatic struct proto uds_proto = { 344219873Spjd .prt_name = "uds", 345219873Spjd .prt_client = uds_client, 346219873Spjd .prt_connect = uds_connect, 347219873Spjd .prt_connect_wait = uds_connect_wait, 348219873Spjd .prt_server = uds_server, 349219873Spjd .prt_accept = uds_accept, 350219873Spjd .prt_send = uds_send, 351219873Spjd .prt_recv = uds_recv, 352219873Spjd .prt_descriptor = uds_descriptor, 353219873Spjd .prt_local_address = uds_local_address, 354219873Spjd .prt_remote_address = uds_remote_address, 355219873Spjd .prt_close = uds_close 356204076Spjd}; 357204076Spjd 358204076Spjdstatic __constructor void 359204076Spjduds_ctor(void) 360204076Spjd{ 361204076Spjd 362210869Spjd proto_register(&uds_proto, false); 363204076Spjd} 364