diff options
Diffstat (limited to 'contrib/blacklist/lib/bl.c')
-rw-r--r-- | contrib/blacklist/lib/bl.c | 527 |
1 files changed, 0 insertions, 527 deletions
diff --git a/contrib/blacklist/lib/bl.c b/contrib/blacklist/lib/bl.c deleted file mode 100644 index 9f93b91f4c8f..000000000000 --- a/contrib/blacklist/lib/bl.c +++ /dev/null @@ -1,527 +0,0 @@ -/* $NetBSD: bl.c,v 1.28 2016/07/29 17:13:09 christos Exp $ */ - -/*- - * Copyright (c) 2014 The NetBSD Foundation, Inc. - * All rights reserved. - * - * This code is derived from software contributed to The NetBSD Foundation - * by Christos Zoulas. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED - * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS - * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include <sys/cdefs.h> -__RCSID("$NetBSD: bl.c,v 1.28 2016/07/29 17:13:09 christos Exp $"); - -#include <sys/param.h> -#include <sys/types.h> -#include <sys/socket.h> -#include <sys/stat.h> -#include <sys/un.h> - -#include <stdio.h> -#include <string.h> -#include <syslog.h> -#include <signal.h> -#include <fcntl.h> -#include <stdlib.h> -#include <unistd.h> -#include <stdint.h> -#include <stdbool.h> -#include <errno.h> -#include <stdarg.h> -#include <netinet/in.h> -#ifdef _REENTRANT -#include <pthread.h> -#endif - -#include "bl.h" - -typedef struct { - uint32_t bl_len; - uint32_t bl_version; - uint32_t bl_type; - uint32_t bl_salen; - struct sockaddr_storage bl_ss; - char bl_data[]; -} bl_message_t; - -struct blacklist { -#ifdef _REENTRANT - pthread_mutex_t b_mutex; -# define BL_INIT(b) pthread_mutex_init(&b->b_mutex, NULL) -# define BL_LOCK(b) pthread_mutex_lock(&b->b_mutex) -# define BL_UNLOCK(b) pthread_mutex_unlock(&b->b_mutex) -#else -# define BL_INIT(b) do {} while(/*CONSTCOND*/0) -# define BL_LOCK(b) BL_INIT(b) -# define BL_UNLOCK(b) BL_INIT(b) -#endif - int b_fd; - int b_connected; - struct sockaddr_un b_sun; - void (*b_fun)(int, const char *, va_list); - bl_info_t b_info; -}; - -#define BL_VERSION 1 - -bool -bl_isconnected(bl_t b) -{ - return b->b_connected == 0; -} - -int -bl_getfd(bl_t b) -{ - return b->b_fd; -} - -static void -bl_reset(bl_t b, bool locked) -{ - int serrno = errno; - if (!locked) - BL_LOCK(b); - close(b->b_fd); - errno = serrno; - b->b_fd = -1; - b->b_connected = -1; - if (!locked) - BL_UNLOCK(b); -} - -static void -bl_log(void (*fun)(int, const char *, va_list), int level, - const char *fmt, ...) -{ - va_list ap; - int serrno = errno; - - va_start(ap, fmt); - (*fun)(level, fmt, ap); - va_end(ap); - errno = serrno; -} - -static int -bl_init(bl_t b, bool srv) -{ - static int one = 1; - /* AF_UNIX address of local logger */ - mode_t om; - int rv, serrno; - struct sockaddr_un *sun = &b->b_sun; - -#ifndef SOCK_NONBLOCK -#define SOCK_NONBLOCK 0 -#endif -#ifndef SOCK_CLOEXEC -#define SOCK_CLOEXEC 0 -#endif -#ifndef SOCK_NOSIGPIPE -#define SOCK_NOSIGPIPE 0 -#endif - - BL_LOCK(b); - - if (b->b_fd == -1) { - b->b_fd = socket(PF_LOCAL, - SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK|SOCK_NOSIGPIPE, 0); - if (b->b_fd == -1) { - bl_log(b->b_fun, LOG_ERR, "%s: socket failed (%s)", - __func__, strerror(errno)); - BL_UNLOCK(b); - return -1; - } -#if SOCK_CLOEXEC == 0 - fcntl(b->b_fd, F_SETFD, FD_CLOEXEC); -#endif -#if SOCK_NONBLOCK == 0 - fcntl(b->b_fd, F_SETFL, fcntl(b->b_fd, F_GETFL) | O_NONBLOCK); -#endif -#if SOCK_NOSIGPIPE == 0 -#ifdef SO_NOSIGPIPE - int o = 1; - setsockopt(b->b_fd, SOL_SOCKET, SO_NOSIGPIPE, &o, sizeof(o)); -#else - signal(SIGPIPE, SIG_IGN); -#endif -#endif - } - - if (bl_isconnected(b)) { - BL_UNLOCK(b); - return 0; - } - - /* - * We try to connect anyway even when we are a server to verify - * that no other server is listening to the socket. If we succeed - * to connect and we are a server, someone else owns it. - */ - rv = connect(b->b_fd, (const void *)sun, (socklen_t)sizeof(*sun)); - if (rv == 0) { - if (srv) { - bl_log(b->b_fun, LOG_ERR, - "%s: another daemon is handling `%s'", - __func__, sun->sun_path); - goto out; - } - } else { - if (!srv) { - /* - * If the daemon is not running, we just try a - * connect, so leave the socket alone until it does - * and only log once. - */ - if (b->b_connected != 1) { - bl_log(b->b_fun, LOG_DEBUG, - "%s: connect failed for `%s' (%s)", - __func__, sun->sun_path, strerror(errno)); - b->b_connected = 1; - } - BL_UNLOCK(b); - return -1; - } - bl_log(b->b_fun, LOG_DEBUG, "Connected to blacklist server", - __func__); - } - - if (srv) { - (void)unlink(sun->sun_path); - om = umask(0); - rv = bind(b->b_fd, (const void *)sun, (socklen_t)sizeof(*sun)); - serrno = errno; - (void)umask(om); - errno = serrno; - if (rv == -1) { - bl_log(b->b_fun, LOG_ERR, - "%s: bind failed for `%s' (%s)", - __func__, sun->sun_path, strerror(errno)); - goto out; - } - } - - b->b_connected = 0; -#define GOT_FD 1 -#if defined(LOCAL_CREDS) -#define CRED_LEVEL 0 -#define CRED_NAME LOCAL_CREDS -#define CRED_SC_UID sc_euid -#define CRED_SC_GID sc_egid -#define CRED_MESSAGE SCM_CREDS -#define CRED_SIZE SOCKCREDSIZE(NGROUPS_MAX) -#define CRED_TYPE struct sockcred -#define GOT_CRED 2 -#elif defined(SO_PASSCRED) -#define CRED_LEVEL SOL_SOCKET -#define CRED_NAME SO_PASSCRED -#define CRED_SC_UID uid -#define CRED_SC_GID gid -#define CRED_MESSAGE SCM_CREDENTIALS -#define CRED_SIZE sizeof(struct ucred) -#define CRED_TYPE struct ucred -#define GOT_CRED 2 -#else -#define GOT_CRED 0 -/* - * getpeereid() and LOCAL_PEERCRED don't help here - * because we are not a stream socket! - */ -#define CRED_SIZE 0 -#define CRED_TYPE void * __unused -#endif - -#ifdef CRED_LEVEL - if (setsockopt(b->b_fd, CRED_LEVEL, CRED_NAME, - &one, (socklen_t)sizeof(one)) == -1) { - bl_log(b->b_fun, LOG_ERR, "%s: setsockopt %s " - "failed (%s)", __func__, __STRING(CRED_NAME), - strerror(errno)); - goto out; - } -#endif - - BL_UNLOCK(b); - return 0; -out: - bl_reset(b, true); - BL_UNLOCK(b); - return -1; -} - -bl_t -bl_create(bool srv, const char *path, void (*fun)(int, const char *, va_list)) -{ - bl_t b = calloc(1, sizeof(*b)); - if (b == NULL) - goto out; - b->b_fun = fun == NULL ? vsyslog : fun; - b->b_fd = -1; - b->b_connected = -1; - BL_INIT(b); - - memset(&b->b_sun, 0, sizeof(b->b_sun)); - b->b_sun.sun_family = AF_LOCAL; -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - b->b_sun.sun_len = sizeof(b->b_sun); -#endif - strlcpy(b->b_sun.sun_path, - path ? path : _PATH_BLSOCK, sizeof(b->b_sun.sun_path)); - - bl_init(b, srv); - return b; -out: - free(b); - bl_log(fun, LOG_ERR, "%s: malloc failed (%s)", __func__, - strerror(errno)); - return NULL; -} - -void -bl_destroy(bl_t b) -{ - bl_reset(b, false); - free(b); -} - -static int -bl_getsock(bl_t b, struct sockaddr_storage *ss, const struct sockaddr *sa, - socklen_t slen, const char *ctx) -{ - uint8_t family; - - memset(ss, 0, sizeof(*ss)); - - switch (slen) { - case 0: - return 0; - case sizeof(struct sockaddr_in): - family = AF_INET; - break; - case sizeof(struct sockaddr_in6): - family = AF_INET6; - break; - default: - bl_log(b->b_fun, LOG_ERR, "%s: invalid socket len %u (%s)", - __func__, (unsigned)slen, ctx); - errno = EINVAL; - return -1; - } - - memcpy(ss, sa, slen); - - if (ss->ss_family != family) { - bl_log(b->b_fun, LOG_INFO, - "%s: correcting socket family %d to %d (%s)", - __func__, ss->ss_family, family, ctx); - ss->ss_family = family; - } - -#ifdef HAVE_STRUCT_SOCKADDR_SA_LEN - if (ss->ss_len != slen) { - bl_log(b->b_fun, LOG_INFO, - "%s: correcting socket len %u to %u (%s)", - __func__, ss->ss_len, (unsigned)slen, ctx); - ss->ss_len = (uint8_t)slen; - } -#endif - return 0; -} - -int -bl_send(bl_t b, bl_type_t e, int pfd, const struct sockaddr *sa, - socklen_t slen, const char *ctx) -{ - struct msghdr msg; - struct iovec iov; - union { - char ctrl[CMSG_SPACE(sizeof(int))]; - uint32_t fd; - } ua; - struct cmsghdr *cmsg; - union { - bl_message_t bl; - char buf[512]; - } ub; - size_t ctxlen, tried; -#define NTRIES 5 - - ctxlen = strlen(ctx); - if (ctxlen > 128) - ctxlen = 128; - - iov.iov_base = ub.buf; - iov.iov_len = sizeof(bl_message_t) + ctxlen; - ub.bl.bl_len = (uint32_t)iov.iov_len; - ub.bl.bl_version = BL_VERSION; - ub.bl.bl_type = (uint32_t)e; - - if (bl_getsock(b, &ub.bl.bl_ss, sa, slen, ctx) == -1) - return -1; - - - ub.bl.bl_salen = slen; - memcpy(ub.bl.bl_data, ctx, ctxlen); - - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_flags = 0; - - msg.msg_control = ua.ctrl; - msg.msg_controllen = sizeof(ua.ctrl); - - cmsg = CMSG_FIRSTHDR(&msg); - cmsg->cmsg_len = CMSG_LEN(sizeof(int)); - cmsg->cmsg_level = SOL_SOCKET; - cmsg->cmsg_type = SCM_RIGHTS; - - memcpy(CMSG_DATA(cmsg), &pfd, sizeof(pfd)); - - tried = 0; -again: - if (bl_init(b, false) == -1) - return -1; - - if ((sendmsg(b->b_fd, &msg, 0) == -1) && tried++ < NTRIES) { - bl_reset(b, false); - goto again; - } - return tried >= NTRIES ? -1 : 0; -} - -bl_info_t * -bl_recv(bl_t b) -{ - struct msghdr msg; - struct iovec iov; - union { - char ctrl[CMSG_SPACE(sizeof(int)) + CMSG_SPACE(CRED_SIZE)]; - uint32_t fd; - CRED_TYPE sc; - } ua; - struct cmsghdr *cmsg; - CRED_TYPE *sc; - union { - bl_message_t bl; - char buf[512]; - } ub; - int got; - ssize_t rlen; - bl_info_t *bi = &b->b_info; - - got = 0; - memset(bi, 0, sizeof(*bi)); - - iov.iov_base = ub.buf; - iov.iov_len = sizeof(ub); - - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_flags = 0; - - msg.msg_control = ua.ctrl; - msg.msg_controllen = sizeof(ua.ctrl) + 100; - - rlen = recvmsg(b->b_fd, &msg, 0); - if (rlen == -1) { - bl_log(b->b_fun, LOG_ERR, "%s: recvmsg failed (%s)", __func__, - strerror(errno)); - return NULL; - } - - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level != SOL_SOCKET) { - bl_log(b->b_fun, LOG_ERR, - "%s: unexpected cmsg_level %d", - __func__, cmsg->cmsg_level); - continue; - } - switch (cmsg->cmsg_type) { - case SCM_RIGHTS: - if (cmsg->cmsg_len != CMSG_LEN(sizeof(int))) { - bl_log(b->b_fun, LOG_ERR, - "%s: unexpected cmsg_len %d != %zu", - __func__, cmsg->cmsg_len, - CMSG_LEN(2 * sizeof(int))); - continue; - } - memcpy(&bi->bi_fd, CMSG_DATA(cmsg), sizeof(bi->bi_fd)); - got |= GOT_FD; - break; -#ifdef CRED_MESSAGE - case CRED_MESSAGE: - sc = (void *)CMSG_DATA(cmsg); - bi->bi_uid = sc->CRED_SC_UID; - bi->bi_gid = sc->CRED_SC_GID; - got |= GOT_CRED; - break; -#endif - default: - bl_log(b->b_fun, LOG_ERR, - "%s: unexpected cmsg_type %d", - __func__, cmsg->cmsg_type); - continue; - } - - } - - if (got != (GOT_CRED|GOT_FD)) { - bl_log(b->b_fun, LOG_ERR, "message missing %s %s", -#if GOT_CRED != 0 - (got & GOT_CRED) == 0 ? "cred" : -#endif - "", (got & GOT_FD) == 0 ? "fd" : ""); - - return NULL; - } - - if ((size_t)rlen <= sizeof(ub.bl)) { - bl_log(b->b_fun, LOG_ERR, "message too short %zd", rlen); - return NULL; - } - - if (ub.bl.bl_version != BL_VERSION) { - bl_log(b->b_fun, LOG_ERR, "bad version %d", ub.bl.bl_version); - return NULL; - } - - bi->bi_type = ub.bl.bl_type; - bi->bi_slen = ub.bl.bl_salen; - bi->bi_ss = ub.bl.bl_ss; -#ifndef CRED_MESSAGE - bi->bi_uid = -1; - bi->bi_gid = -1; -#endif - strlcpy(bi->bi_msg, ub.bl.bl_data, MIN(sizeof(bi->bi_msg), - ((size_t)rlen - sizeof(ub.bl) + 1))); - return bi; -} |