1318239Slidl/* $NetBSD: bl.c,v 1.28 2016/07/29 17:13:09 christos Exp $ */ 2301169Slidl 3301169Slidl/*- 4301169Slidl * Copyright (c) 2014 The NetBSD Foundation, Inc. 5301169Slidl * All rights reserved. 6301169Slidl * 7301169Slidl * This code is derived from software contributed to The NetBSD Foundation 8301169Slidl * by Christos Zoulas. 9301169Slidl * 10301169Slidl * Redistribution and use in source and binary forms, with or without 11301169Slidl * modification, are permitted provided that the following conditions 12301169Slidl * are met: 13301169Slidl * 1. Redistributions of source code must retain the above copyright 14301169Slidl * notice, this list of conditions and the following disclaimer. 15301169Slidl * 2. Redistributions in binary form must reproduce the above copyright 16301169Slidl * notice, this list of conditions and the following disclaimer in the 17301169Slidl * documentation and/or other materials provided with the distribution. 18301169Slidl * 19301169Slidl * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20301169Slidl * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21301169Slidl * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22301169Slidl * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23301169Slidl * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24301169Slidl * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25301169Slidl * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26301169Slidl * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27301169Slidl * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28301169Slidl * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29301169Slidl * POSSIBILITY OF SUCH DAMAGE. 30301169Slidl */ 31301169Slidl#ifdef HAVE_CONFIG_H 32301169Slidl#include "config.h" 33301169Slidl#endif 34301169Slidl 35301169Slidl#include <sys/cdefs.h> 36318239Slidl__RCSID("$NetBSD: bl.c,v 1.28 2016/07/29 17:13:09 christos Exp $"); 37301169Slidl 38301169Slidl#include <sys/param.h> 39301169Slidl#include <sys/types.h> 40301169Slidl#include <sys/socket.h> 41301169Slidl#include <sys/stat.h> 42301169Slidl#include <sys/un.h> 43301169Slidl 44301169Slidl#include <stdio.h> 45301169Slidl#include <string.h> 46301169Slidl#include <syslog.h> 47301169Slidl#include <signal.h> 48301169Slidl#include <fcntl.h> 49301169Slidl#include <stdlib.h> 50301169Slidl#include <unistd.h> 51301169Slidl#include <stdint.h> 52301169Slidl#include <stdbool.h> 53301169Slidl#include <errno.h> 54301169Slidl#include <stdarg.h> 55301169Slidl#include <netinet/in.h> 56301169Slidl#ifdef _REENTRANT 57301169Slidl#include <pthread.h> 58301169Slidl#endif 59301169Slidl 60301169Slidl#include "bl.h" 61301169Slidl 62301169Slidltypedef struct { 63301169Slidl uint32_t bl_len; 64301169Slidl uint32_t bl_version; 65301169Slidl uint32_t bl_type; 66301169Slidl uint32_t bl_salen; 67301169Slidl struct sockaddr_storage bl_ss; 68301169Slidl char bl_data[]; 69301169Slidl} bl_message_t; 70301169Slidl 71301169Slidlstruct blacklist { 72301169Slidl#ifdef _REENTRANT 73301169Slidl pthread_mutex_t b_mutex; 74301169Slidl# define BL_INIT(b) pthread_mutex_init(&b->b_mutex, NULL) 75301169Slidl# define BL_LOCK(b) pthread_mutex_lock(&b->b_mutex) 76301169Slidl# define BL_UNLOCK(b) pthread_mutex_unlock(&b->b_mutex) 77301169Slidl#else 78301169Slidl# define BL_INIT(b) do {} while(/*CONSTCOND*/0) 79301169Slidl# define BL_LOCK(b) BL_INIT(b) 80301169Slidl# define BL_UNLOCK(b) BL_INIT(b) 81301169Slidl#endif 82301169Slidl int b_fd; 83301169Slidl int b_connected; 84301169Slidl struct sockaddr_un b_sun; 85301169Slidl void (*b_fun)(int, const char *, va_list); 86301169Slidl bl_info_t b_info; 87301169Slidl}; 88301169Slidl 89301169Slidl#define BL_VERSION 1 90301169Slidl 91301169Slidlbool 92301169Slidlbl_isconnected(bl_t b) 93301169Slidl{ 94301169Slidl return b->b_connected == 0; 95301169Slidl} 96301169Slidl 97301169Slidlint 98301169Slidlbl_getfd(bl_t b) 99301169Slidl{ 100301169Slidl return b->b_fd; 101301169Slidl} 102301169Slidl 103301169Slidlstatic void 104301169Slidlbl_reset(bl_t b, bool locked) 105301169Slidl{ 106301169Slidl int serrno = errno; 107301169Slidl if (!locked) 108301169Slidl BL_LOCK(b); 109301169Slidl close(b->b_fd); 110301169Slidl errno = serrno; 111301169Slidl b->b_fd = -1; 112301169Slidl b->b_connected = -1; 113301169Slidl if (!locked) 114301169Slidl BL_UNLOCK(b); 115301169Slidl} 116301169Slidl 117301169Slidlstatic void 118301169Slidlbl_log(void (*fun)(int, const char *, va_list), int level, 119301169Slidl const char *fmt, ...) 120301169Slidl{ 121301169Slidl va_list ap; 122301169Slidl int serrno = errno; 123301169Slidl 124301169Slidl va_start(ap, fmt); 125301169Slidl (*fun)(level, fmt, ap); 126301169Slidl va_end(ap); 127301169Slidl errno = serrno; 128301169Slidl} 129301169Slidl 130301169Slidlstatic int 131301169Slidlbl_init(bl_t b, bool srv) 132301169Slidl{ 133301169Slidl static int one = 1; 134301169Slidl /* AF_UNIX address of local logger */ 135301169Slidl mode_t om; 136301169Slidl int rv, serrno; 137301169Slidl struct sockaddr_un *sun = &b->b_sun; 138301169Slidl 139301169Slidl#ifndef SOCK_NONBLOCK 140301169Slidl#define SOCK_NONBLOCK 0 141301169Slidl#endif 142301169Slidl#ifndef SOCK_CLOEXEC 143301169Slidl#define SOCK_CLOEXEC 0 144301169Slidl#endif 145301169Slidl#ifndef SOCK_NOSIGPIPE 146301169Slidl#define SOCK_NOSIGPIPE 0 147301169Slidl#endif 148301169Slidl 149301169Slidl BL_LOCK(b); 150301169Slidl 151301169Slidl if (b->b_fd == -1) { 152301169Slidl b->b_fd = socket(PF_LOCAL, 153301169Slidl SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK|SOCK_NOSIGPIPE, 0); 154301169Slidl if (b->b_fd == -1) { 155304028Slidl bl_log(b->b_fun, LOG_ERR, "%s: socket failed (%s)", 156304028Slidl __func__, strerror(errno)); 157301169Slidl BL_UNLOCK(b); 158301169Slidl return -1; 159301169Slidl } 160301169Slidl#if SOCK_CLOEXEC == 0 161301169Slidl fcntl(b->b_fd, F_SETFD, FD_CLOEXEC); 162301169Slidl#endif 163301169Slidl#if SOCK_NONBLOCK == 0 164301169Slidl fcntl(b->b_fd, F_SETFL, fcntl(b->b_fd, F_GETFL) | O_NONBLOCK); 165301169Slidl#endif 166301169Slidl#if SOCK_NOSIGPIPE == 0 167301169Slidl#ifdef SO_NOSIGPIPE 168301169Slidl int o = 1; 169301169Slidl setsockopt(b->b_fd, SOL_SOCKET, SO_NOSIGPIPE, &o, sizeof(o)); 170301169Slidl#else 171301169Slidl signal(SIGPIPE, SIG_IGN); 172301169Slidl#endif 173301169Slidl#endif 174301169Slidl } 175301169Slidl 176301169Slidl if (bl_isconnected(b)) { 177301169Slidl BL_UNLOCK(b); 178301169Slidl return 0; 179301169Slidl } 180301169Slidl 181301169Slidl /* 182301169Slidl * We try to connect anyway even when we are a server to verify 183301169Slidl * that no other server is listening to the socket. If we succeed 184301169Slidl * to connect and we are a server, someone else owns it. 185301169Slidl */ 186301169Slidl rv = connect(b->b_fd, (const void *)sun, (socklen_t)sizeof(*sun)); 187301169Slidl if (rv == 0) { 188301169Slidl if (srv) { 189301169Slidl bl_log(b->b_fun, LOG_ERR, 190301169Slidl "%s: another daemon is handling `%s'", 191301169Slidl __func__, sun->sun_path); 192301169Slidl goto out; 193301169Slidl } 194301169Slidl } else { 195301169Slidl if (!srv) { 196301169Slidl /* 197301169Slidl * If the daemon is not running, we just try a 198301169Slidl * connect, so leave the socket alone until it does 199301169Slidl * and only log once. 200301169Slidl */ 201301169Slidl if (b->b_connected != 1) { 202301169Slidl bl_log(b->b_fun, LOG_DEBUG, 203304028Slidl "%s: connect failed for `%s' (%s)", 204304028Slidl __func__, sun->sun_path, strerror(errno)); 205301169Slidl b->b_connected = 1; 206301169Slidl } 207301169Slidl BL_UNLOCK(b); 208301169Slidl return -1; 209301169Slidl } 210301169Slidl bl_log(b->b_fun, LOG_DEBUG, "Connected to blacklist server", 211301169Slidl __func__); 212301169Slidl } 213301169Slidl 214301169Slidl if (srv) { 215301169Slidl (void)unlink(sun->sun_path); 216301169Slidl om = umask(0); 217301169Slidl rv = bind(b->b_fd, (const void *)sun, (socklen_t)sizeof(*sun)); 218301169Slidl serrno = errno; 219301169Slidl (void)umask(om); 220301169Slidl errno = serrno; 221301169Slidl if (rv == -1) { 222301169Slidl bl_log(b->b_fun, LOG_ERR, 223304028Slidl "%s: bind failed for `%s' (%s)", 224304028Slidl __func__, sun->sun_path, strerror(errno)); 225301169Slidl goto out; 226301169Slidl } 227301169Slidl } 228301169Slidl 229301169Slidl b->b_connected = 0; 230301169Slidl#define GOT_FD 1 231301169Slidl#if defined(LOCAL_CREDS) 232301169Slidl#define CRED_LEVEL 0 233301169Slidl#define CRED_NAME LOCAL_CREDS 234301169Slidl#define CRED_SC_UID sc_euid 235301169Slidl#define CRED_SC_GID sc_egid 236301169Slidl#define CRED_MESSAGE SCM_CREDS 237301169Slidl#define CRED_SIZE SOCKCREDSIZE(NGROUPS_MAX) 238301169Slidl#define CRED_TYPE struct sockcred 239301169Slidl#define GOT_CRED 2 240301169Slidl#elif defined(SO_PASSCRED) 241301169Slidl#define CRED_LEVEL SOL_SOCKET 242301169Slidl#define CRED_NAME SO_PASSCRED 243301169Slidl#define CRED_SC_UID uid 244301169Slidl#define CRED_SC_GID gid 245301169Slidl#define CRED_MESSAGE SCM_CREDENTIALS 246301169Slidl#define CRED_SIZE sizeof(struct ucred) 247301169Slidl#define CRED_TYPE struct ucred 248301169Slidl#define GOT_CRED 2 249301169Slidl#else 250301169Slidl#define GOT_CRED 0 251301169Slidl/* 252301169Slidl * getpeereid() and LOCAL_PEERCRED don't help here 253301169Slidl * because we are not a stream socket! 254301169Slidl */ 255301169Slidl#define CRED_SIZE 0 256301169Slidl#define CRED_TYPE void * __unused 257301169Slidl#endif 258301169Slidl 259301169Slidl#ifdef CRED_LEVEL 260301169Slidl if (setsockopt(b->b_fd, CRED_LEVEL, CRED_NAME, 261301169Slidl &one, (socklen_t)sizeof(one)) == -1) { 262301169Slidl bl_log(b->b_fun, LOG_ERR, "%s: setsockopt %s " 263304028Slidl "failed (%s)", __func__, __STRING(CRED_NAME), 264304028Slidl strerror(errno)); 265301169Slidl goto out; 266301169Slidl } 267301169Slidl#endif 268301169Slidl 269301169Slidl BL_UNLOCK(b); 270301169Slidl return 0; 271301169Slidlout: 272301169Slidl bl_reset(b, true); 273301169Slidl BL_UNLOCK(b); 274301169Slidl return -1; 275301169Slidl} 276301169Slidl 277301169Slidlbl_t 278301169Slidlbl_create(bool srv, const char *path, void (*fun)(int, const char *, va_list)) 279301169Slidl{ 280301169Slidl bl_t b = calloc(1, sizeof(*b)); 281301169Slidl if (b == NULL) 282301169Slidl goto out; 283301169Slidl b->b_fun = fun == NULL ? vsyslog : fun; 284301169Slidl b->b_fd = -1; 285301169Slidl b->b_connected = -1; 286301169Slidl BL_INIT(b); 287301169Slidl 288301169Slidl memset(&b->b_sun, 0, sizeof(b->b_sun)); 289301169Slidl b->b_sun.sun_family = AF_LOCAL; 290301169Slidl#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 291301169Slidl b->b_sun.sun_len = sizeof(b->b_sun); 292301169Slidl#endif 293301169Slidl strlcpy(b->b_sun.sun_path, 294301169Slidl path ? path : _PATH_BLSOCK, sizeof(b->b_sun.sun_path)); 295301169Slidl 296301169Slidl bl_init(b, srv); 297301169Slidl return b; 298301169Slidlout: 299301169Slidl free(b); 300304028Slidl bl_log(fun, LOG_ERR, "%s: malloc failed (%s)", __func__, 301304028Slidl strerror(errno)); 302301169Slidl return NULL; 303301169Slidl} 304301169Slidl 305301169Slidlvoid 306301169Slidlbl_destroy(bl_t b) 307301169Slidl{ 308301169Slidl bl_reset(b, false); 309301169Slidl free(b); 310301169Slidl} 311301169Slidl 312301169Slidlstatic int 313301169Slidlbl_getsock(bl_t b, struct sockaddr_storage *ss, const struct sockaddr *sa, 314301169Slidl socklen_t slen, const char *ctx) 315301169Slidl{ 316301169Slidl uint8_t family; 317301169Slidl 318301169Slidl memset(ss, 0, sizeof(*ss)); 319301169Slidl 320301169Slidl switch (slen) { 321301169Slidl case 0: 322301169Slidl return 0; 323301169Slidl case sizeof(struct sockaddr_in): 324301169Slidl family = AF_INET; 325301169Slidl break; 326301169Slidl case sizeof(struct sockaddr_in6): 327301169Slidl family = AF_INET6; 328301169Slidl break; 329301169Slidl default: 330301169Slidl bl_log(b->b_fun, LOG_ERR, "%s: invalid socket len %u (%s)", 331301169Slidl __func__, (unsigned)slen, ctx); 332301169Slidl errno = EINVAL; 333301169Slidl return -1; 334301169Slidl } 335301169Slidl 336301169Slidl memcpy(ss, sa, slen); 337301169Slidl 338301169Slidl if (ss->ss_family != family) { 339301169Slidl bl_log(b->b_fun, LOG_INFO, 340301169Slidl "%s: correcting socket family %d to %d (%s)", 341301169Slidl __func__, ss->ss_family, family, ctx); 342301169Slidl ss->ss_family = family; 343301169Slidl } 344301169Slidl 345301169Slidl#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN 346301169Slidl if (ss->ss_len != slen) { 347301169Slidl bl_log(b->b_fun, LOG_INFO, 348301169Slidl "%s: correcting socket len %u to %u (%s)", 349301169Slidl __func__, ss->ss_len, (unsigned)slen, ctx); 350301169Slidl ss->ss_len = (uint8_t)slen; 351301169Slidl } 352301169Slidl#endif 353301169Slidl return 0; 354301169Slidl} 355301169Slidl 356301169Slidlint 357301169Slidlbl_send(bl_t b, bl_type_t e, int pfd, const struct sockaddr *sa, 358301169Slidl socklen_t slen, const char *ctx) 359301169Slidl{ 360301169Slidl struct msghdr msg; 361301169Slidl struct iovec iov; 362301169Slidl union { 363301169Slidl char ctrl[CMSG_SPACE(sizeof(int))]; 364301169Slidl uint32_t fd; 365301169Slidl } ua; 366301169Slidl struct cmsghdr *cmsg; 367301169Slidl union { 368301169Slidl bl_message_t bl; 369301169Slidl char buf[512]; 370301169Slidl } ub; 371301169Slidl size_t ctxlen, tried; 372301169Slidl#define NTRIES 5 373301169Slidl 374301169Slidl ctxlen = strlen(ctx); 375301169Slidl if (ctxlen > 128) 376301169Slidl ctxlen = 128; 377301169Slidl 378301169Slidl iov.iov_base = ub.buf; 379301169Slidl iov.iov_len = sizeof(bl_message_t) + ctxlen; 380301169Slidl ub.bl.bl_len = (uint32_t)iov.iov_len; 381301169Slidl ub.bl.bl_version = BL_VERSION; 382301169Slidl ub.bl.bl_type = (uint32_t)e; 383301169Slidl 384301169Slidl if (bl_getsock(b, &ub.bl.bl_ss, sa, slen, ctx) == -1) 385301169Slidl return -1; 386301169Slidl 387301169Slidl 388301169Slidl ub.bl.bl_salen = slen; 389301169Slidl memcpy(ub.bl.bl_data, ctx, ctxlen); 390301169Slidl 391301169Slidl msg.msg_name = NULL; 392301169Slidl msg.msg_namelen = 0; 393301169Slidl msg.msg_iov = &iov; 394301169Slidl msg.msg_iovlen = 1; 395301169Slidl msg.msg_flags = 0; 396301169Slidl 397301169Slidl msg.msg_control = ua.ctrl; 398301169Slidl msg.msg_controllen = sizeof(ua.ctrl); 399301169Slidl 400301169Slidl cmsg = CMSG_FIRSTHDR(&msg); 401301169Slidl cmsg->cmsg_len = CMSG_LEN(sizeof(int)); 402301169Slidl cmsg->cmsg_level = SOL_SOCKET; 403301169Slidl cmsg->cmsg_type = SCM_RIGHTS; 404301169Slidl 405301169Slidl memcpy(CMSG_DATA(cmsg), &pfd, sizeof(pfd)); 406301169Slidl 407301169Slidl tried = 0; 408301169Slidlagain: 409301169Slidl if (bl_init(b, false) == -1) 410301169Slidl return -1; 411301169Slidl 412301169Slidl if ((sendmsg(b->b_fd, &msg, 0) == -1) && tried++ < NTRIES) { 413301169Slidl bl_reset(b, false); 414301169Slidl goto again; 415301169Slidl } 416301169Slidl return tried >= NTRIES ? -1 : 0; 417301169Slidl} 418301169Slidl 419301169Slidlbl_info_t * 420301169Slidlbl_recv(bl_t b) 421301169Slidl{ 422301169Slidl struct msghdr msg; 423301169Slidl struct iovec iov; 424301169Slidl union { 425301169Slidl char ctrl[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(CRED_SIZE)]; 426301169Slidl uint32_t fd; 427301169Slidl CRED_TYPE sc; 428301169Slidl } ua; 429301169Slidl struct cmsghdr *cmsg; 430301169Slidl CRED_TYPE *sc; 431301169Slidl union { 432301169Slidl bl_message_t bl; 433301169Slidl char buf[512]; 434301169Slidl } ub; 435301169Slidl int got; 436301169Slidl ssize_t rlen; 437301169Slidl bl_info_t *bi = &b->b_info; 438301169Slidl 439301169Slidl got = 0; 440301169Slidl memset(bi, 0, sizeof(*bi)); 441301169Slidl 442301169Slidl iov.iov_base = ub.buf; 443301169Slidl iov.iov_len = sizeof(ub); 444301169Slidl 445301169Slidl msg.msg_name = NULL; 446301169Slidl msg.msg_namelen = 0; 447301169Slidl msg.msg_iov = &iov; 448301169Slidl msg.msg_iovlen = 1; 449301169Slidl msg.msg_flags = 0; 450301169Slidl 451301169Slidl msg.msg_control = ua.ctrl; 452301169Slidl msg.msg_controllen = sizeof(ua.ctrl) + 100; 453301169Slidl 454301169Slidl rlen = recvmsg(b->b_fd, &msg, 0); 455301169Slidl if (rlen == -1) { 456304028Slidl bl_log(b->b_fun, LOG_ERR, "%s: recvmsg failed (%s)", __func__, 457304028Slidl strerror(errno)); 458301169Slidl return NULL; 459301169Slidl } 460301169Slidl 461301169Slidl for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { 462301169Slidl if (cmsg->cmsg_level != SOL_SOCKET) { 463301169Slidl bl_log(b->b_fun, LOG_ERR, 464301169Slidl "%s: unexpected cmsg_level %d", 465301169Slidl __func__, cmsg->cmsg_level); 466301169Slidl continue; 467301169Slidl } 468301169Slidl switch (cmsg->cmsg_type) { 469301169Slidl case SCM_RIGHTS: 470301169Slidl if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) { 471301169Slidl bl_log(b->b_fun, LOG_ERR, 472301169Slidl "%s: unexpected cmsg_len %d != %zu", 473301169Slidl __func__, cmsg->cmsg_len, 474301169Slidl CMSG_LEN(2 * sizeof(int))); 475301169Slidl continue; 476301169Slidl } 477301169Slidl memcpy(&bi->bi_fd, CMSG_DATA(cmsg), sizeof(bi->bi_fd)); 478301169Slidl got |= GOT_FD; 479301169Slidl break; 480301169Slidl#ifdef CRED_MESSAGE 481301169Slidl case CRED_MESSAGE: 482301169Slidl sc = (void *)CMSG_DATA(cmsg); 483301169Slidl bi->bi_uid = sc->CRED_SC_UID; 484301169Slidl bi->bi_gid = sc->CRED_SC_GID; 485301169Slidl got |= GOT_CRED; 486301169Slidl break; 487301169Slidl#endif 488301169Slidl default: 489301169Slidl bl_log(b->b_fun, LOG_ERR, 490301169Slidl "%s: unexpected cmsg_type %d", 491301169Slidl __func__, cmsg->cmsg_type); 492301169Slidl continue; 493301169Slidl } 494301169Slidl 495301169Slidl } 496301169Slidl 497301169Slidl if (got != (GOT_CRED|GOT_FD)) { 498301169Slidl bl_log(b->b_fun, LOG_ERR, "message missing %s %s", 499301169Slidl#if GOT_CRED != 0 500301169Slidl (got & GOT_CRED) == 0 ? "cred" : 501301169Slidl#endif 502301169Slidl "", (got & GOT_FD) == 0 ? "fd" : ""); 503301169Slidl 504301169Slidl return NULL; 505301169Slidl } 506301169Slidl 507301169Slidl if ((size_t)rlen <= sizeof(ub.bl)) { 508301169Slidl bl_log(b->b_fun, LOG_ERR, "message too short %zd", rlen); 509301169Slidl return NULL; 510301169Slidl } 511301169Slidl 512301169Slidl if (ub.bl.bl_version != BL_VERSION) { 513301169Slidl bl_log(b->b_fun, LOG_ERR, "bad version %d", ub.bl.bl_version); 514301169Slidl return NULL; 515301169Slidl } 516301169Slidl 517301169Slidl bi->bi_type = ub.bl.bl_type; 518301169Slidl bi->bi_slen = ub.bl.bl_salen; 519301169Slidl bi->bi_ss = ub.bl.bl_ss; 520301169Slidl#ifndef CRED_MESSAGE 521301169Slidl bi->bi_uid = -1; 522301169Slidl bi->bi_gid = -1; 523301169Slidl#endif 524301169Slidl strlcpy(bi->bi_msg, ub.bl.bl_data, MIN(sizeof(bi->bi_msg), 525301169Slidl ((size_t)rlen - sizeof(ub.bl) + 1))); 526301169Slidl return bi; 527301169Slidl} 528