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