1 /* $NetBSD: bl.c,v 1.26 2015/05/28 01:01:37 christos Exp $ */
4 * Copyright (c) 2014 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
35 #include <sys/cdefs.h>
36 __RCSID("$NetBSD: bl.c,v 1.26 2015/05/28 01:01:37 christos Exp $");
38 #include <sys/param.h>
39 #include <sys/types.h>
40 #include <sys/socket.h>
55 #include <netinet/in.h>
64 struct sockaddr_storage bl_ss
;
71 struct sockaddr_un b_sun
;
72 void (*b_fun
)(int, const char *, va_list);
79 bl_isconnected(bl_t b
)
81 return b
->b_connected
== 0;
101 bl_log(void (*fun
)(int, const char *, va_list), int level
,
102 const char *fmt
, ...)
108 (*fun
)(level
, fmt
, ap
);
114 bl_init(bl_t b
, bool srv
)
117 /* AF_UNIX address of local logger */
120 struct sockaddr_un
*sun
= &b
->b_sun
;
122 #ifndef SOCK_NONBLOCK
123 #define SOCK_NONBLOCK 0
126 #define SOCK_CLOEXEC 0
128 #ifndef SOCK_NOSIGPIPE
129 #define SOCK_NOSIGPIPE 0
133 b
->b_fd
= socket(PF_LOCAL
,
134 SOCK_DGRAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
|SOCK_NOSIGPIPE
, 0);
136 bl_log(b
->b_fun
, LOG_ERR
, "%s: socket failed (%m)",
140 #if SOCK_CLOEXEC == 0
141 fcntl(b
->b_fd
, F_SETFD
, FD_CLOEXEC
);
143 #if SOCK_NONBLOCK == 0
144 fcntl(b
->b_fd
, F_SETFL
, fcntl(b
->b_fd
, F_GETFL
) | O_NONBLOCK
);
146 #if SOCK_NOSIGPIPE == 0
149 setsockopt(b
->b_fd
, SOL_SOCKET
, SO_NOSIGPIPE
, &o
, sizeof(o
));
151 signal(SIGPIPE
, SIG_IGN
);
156 if (bl_isconnected(b
))
159 rv
= connect(b
->b_fd
, (const void *)sun
, (socklen_t
)sizeof(*sun
));
162 bl_log(b
->b_fun
, LOG_ERR
,
163 "%s: another daemon is handling `%s'",
164 __func__
, sun
->sun_path
);
170 * If the daemon is not running, we just try a
171 * connect, so leave the socket alone until it does
174 if (b
->b_connected
!= 1) {
175 bl_log(b
->b_fun
, LOG_DEBUG
,
176 "%s: connect failed for `%s' (%m)",
177 __func__
, sun
->sun_path
);
182 bl_log(b
->b_fun
, LOG_DEBUG
, "Connected to blacklist server",
187 (void)unlink(sun
->sun_path
);
189 rv
= bind(b
->b_fd
, (const void *)sun
, (socklen_t
)sizeof(*sun
));
194 bl_log(b
->b_fun
, LOG_ERR
,
195 "%s: bind failed for `%s' (%m)",
196 __func__
, sun
->sun_path
);
203 #if defined(LOCAL_CREDS)
205 #define CRED_NAME LOCAL_CREDS
206 #define CRED_SC_UID sc_euid
207 #define CRED_SC_GID sc_egid
208 #define CRED_MESSAGE SCM_CREDS
209 #define CRED_SIZE SOCKCREDSIZE(NGROUPS_MAX)
210 #define CRED_TYPE struct sockcred
212 #elif defined(SO_PASSCRED)
213 #define CRED_LEVEL SOL_SOCKET
214 #define CRED_NAME SO_PASSCRED
215 #define CRED_SC_UID uid
216 #define CRED_SC_GID gid
217 #define CRED_MESSAGE SCM_CREDENTIALS
218 #define CRED_SIZE sizeof(struct ucred)
219 #define CRED_TYPE struct ucred
224 * getpeereid() and LOCAL_PEERCRED don't help here
225 * because we are not a stream socket!
228 #define CRED_TYPE void * __unused
232 if (setsockopt(b
->b_fd
, CRED_LEVEL
, CRED_NAME
,
233 &one
, (socklen_t
)sizeof(one
)) == -1) {
234 bl_log(b
->b_fun
, LOG_ERR
, "%s: setsockopt %s "
235 "failed (%m)", __func__
, __STRING(CRED_NAME
));
247 bl_create(bool srv
, const char *path
, void (*fun
)(int, const char *, va_list))
249 bl_t b
= calloc(1, sizeof(*b
));
252 b
->b_fun
= fun
== NULL
? vsyslog
: fun
;
256 memset(&b
->b_sun
, 0, sizeof(b
->b_sun
));
257 b
->b_sun
.sun_family
= AF_LOCAL
;
258 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
259 b
->b_sun
.sun_len
= sizeof(b
->b_sun
);
261 strlcpy(b
->b_sun
.sun_path
,
262 path
? path
: _PATH_BLSOCK
, sizeof(b
->b_sun
.sun_path
));
268 bl_log(fun
, LOG_ERR
, "%s: malloc failed (%m)", __func__
);
280 bl_getsock(bl_t b
, struct sockaddr_storage
*ss
, const struct sockaddr
*sa
,
281 socklen_t slen
, const char *ctx
)
285 memset(ss
, 0, sizeof(*ss
));
290 case sizeof(struct sockaddr_in
):
293 case sizeof(struct sockaddr_in6
):
297 bl_log(b
->b_fun
, LOG_ERR
, "%s: invalid socket len %u (%s)",
298 __func__
, (unsigned)slen
, ctx
);
303 memcpy(ss
, sa
, slen
);
305 if (ss
->ss_family
!= family
) {
306 bl_log(b
->b_fun
, LOG_INFO
,
307 "%s: correcting socket family %d to %d (%s)",
308 __func__
, ss
->ss_family
, family
, ctx
);
309 ss
->ss_family
= family
;
312 #ifdef HAVE_STRUCT_SOCKADDR_SA_LEN
313 if (ss
->ss_len
!= slen
) {
314 bl_log(b
->b_fun
, LOG_INFO
,
315 "%s: correcting socket len %u to %u (%s)",
316 __func__
, ss
->ss_len
, (unsigned)slen
, ctx
);
317 ss
->ss_len
= (uint8_t)slen
;
324 bl_send(bl_t b
, bl_type_t e
, int pfd
, const struct sockaddr
*sa
,
325 socklen_t slen
, const char *ctx
)
330 char ctrl
[CMSG_SPACE(sizeof(int))];
333 struct cmsghdr
*cmsg
;
338 size_t ctxlen
, tried
;
341 ctxlen
= strlen(ctx
);
345 iov
.iov_base
= ub
.buf
;
346 iov
.iov_len
= sizeof(bl_message_t
) + ctxlen
;
347 ub
.bl
.bl_len
= (uint32_t)iov
.iov_len
;
348 ub
.bl
.bl_version
= BL_VERSION
;
349 ub
.bl
.bl_type
= (uint32_t)e
;
351 if (bl_getsock(b
, &ub
.bl
.bl_ss
, sa
, slen
, ctx
) == -1)
355 ub
.bl
.bl_salen
= slen
;
356 memcpy(ub
.bl
.bl_data
, ctx
, ctxlen
);
364 msg
.msg_control
= ua
.ctrl
;
365 msg
.msg_controllen
= sizeof(ua
.ctrl
);
367 cmsg
= CMSG_FIRSTHDR(&msg
);
368 cmsg
->cmsg_len
= CMSG_LEN(sizeof(int));
369 cmsg
->cmsg_level
= SOL_SOCKET
;
370 cmsg
->cmsg_type
= SCM_RIGHTS
;
372 memcpy(CMSG_DATA(cmsg
), &pfd
, sizeof(pfd
));
376 if (bl_init(b
, false) == -1)
379 if ((sendmsg(b
->b_fd
, &msg
, 0) == -1) && tried
++ < NTRIES
) {
383 return tried
>= NTRIES
? -1 : 0;
392 char ctrl
[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(CRED_SIZE
)];
396 struct cmsghdr
*cmsg
;
404 bl_info_t
*bi
= &b
->b_info
;
407 memset(bi
, 0, sizeof(*bi
));
409 iov
.iov_base
= ub
.buf
;
410 iov
.iov_len
= sizeof(ub
);
418 msg
.msg_control
= ua
.ctrl
;
419 msg
.msg_controllen
= sizeof(ua
.ctrl
) + 100;
421 rlen
= recvmsg(b
->b_fd
, &msg
, 0);
423 bl_log(b
->b_fun
, LOG_ERR
, "%s: recvmsg failed (%m)", __func__
);
427 for (cmsg
= CMSG_FIRSTHDR(&msg
); cmsg
; cmsg
= CMSG_NXTHDR(&msg
, cmsg
)) {
428 if (cmsg
->cmsg_level
!= SOL_SOCKET
) {
429 bl_log(b
->b_fun
, LOG_ERR
,
430 "%s: unexpected cmsg_level %d",
431 __func__
, cmsg
->cmsg_level
);
434 switch (cmsg
->cmsg_type
) {
436 if (cmsg
->cmsg_len
!= CMSG_LEN(sizeof(int))) {
437 bl_log(b
->b_fun
, LOG_ERR
,
438 "%s: unexpected cmsg_len %d != %zu",
439 __func__
, cmsg
->cmsg_len
,
440 CMSG_LEN(2 * sizeof(int)));
443 memcpy(&bi
->bi_fd
, CMSG_DATA(cmsg
), sizeof(bi
->bi_fd
));
448 sc
= (void *)CMSG_DATA(cmsg
);
449 bi
->bi_uid
= sc
->CRED_SC_UID
;
450 bi
->bi_gid
= sc
->CRED_SC_GID
;
455 bl_log(b
->b_fun
, LOG_ERR
,
456 "%s: unexpected cmsg_type %d",
457 __func__
, cmsg
->cmsg_type
);
463 if (got
!= (GOT_CRED
|GOT_FD
)) {
464 bl_log(b
->b_fun
, LOG_ERR
, "message missing %s %s",
466 (got
& GOT_CRED
) == 0 ? "cred" :
468 "", (got
& GOT_FD
) == 0 ? "fd" : "");
473 if ((size_t)rlen
<= sizeof(ub
.bl
)) {
474 bl_log(b
->b_fun
, LOG_ERR
, "message too short %zd", rlen
);
478 if (ub
.bl
.bl_version
!= BL_VERSION
) {
479 bl_log(b
->b_fun
, LOG_ERR
, "bad version %d", ub
.bl
.bl_version
);
483 bi
->bi_type
= ub
.bl
.bl_type
;
484 bi
->bi_slen
= ub
.bl
.bl_salen
;
485 bi
->bi_ss
= ub
.bl
.bl_ss
;
490 strlcpy(bi
->bi_msg
, ub
.bl
.bl_data
, MIN(sizeof(bi
->bi_msg
),
491 ((size_t)rlen
- sizeof(ub
.bl
) + 1)));