Beispiel #1
0
static void
addfd(struct pollfd **pfdp, bl_t **blp, size_t *nfd, size_t *maxfd,
    const char *path)
{
	bl_t bl = bl_create(true, path, vflag ? vdlog : vsyslog);
	if (bl == NULL || !bl_isconnected(bl))
		exit(EXIT_FAILURE);
	if (*nfd >= *maxfd) {
		*maxfd += 10;
		*blp = realloc(*blp, sizeof(**blp) * *maxfd);
		if (*blp == NULL)
			err(EXIT_FAILURE, "malloc");
		*pfdp = realloc(*pfdp, sizeof(**pfdp) * *maxfd);
		if (*pfdp == NULL)
			err(EXIT_FAILURE, "malloc");
	}

	(*pfdp)[*nfd].fd = bl_getfd(bl);
	(*pfdp)[*nfd].events = POLLIN;
	(*blp)[*nfd] = bl;
	*nfd += 1;
}
Beispiel #2
0
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 (%m)",
			    __func__);
			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' (%m)",
				    __func__, sun->sun_path);
				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' (%m)",
			    __func__, sun->sun_path);
			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 (%m)", __func__, __STRING(CRED_NAME));
		goto out;
	}
#endif

	BL_UNLOCK(b);
	return 0;
out:
	bl_reset(b, true);
	BL_UNLOCK(b);
	return -1;
}