Blame libnetlabel/netlabel_comm.c

Packit 51d0f7
/** @file
Packit 51d0f7
 * NetLabel Low-Level Communication Functions
Packit 51d0f7
 *
Packit 51d0f7
 * Author: Paul Moore <paul@paul-moore.com>
Packit 51d0f7
 *
Packit 51d0f7
 */
Packit 51d0f7
Packit 51d0f7
/*
Packit 51d0f7
 * (c) Copyright Hewlett-Packard Development Company, L.P., 2006
Packit 51d0f7
 *
Packit 51d0f7
 * This program is free software: you can redistribute it and/or modify
Packit 51d0f7
 * it under the terms of version 2 of the GNU General Public License as
Packit 51d0f7
 * published by the Free Software Foundation.
Packit 51d0f7
 *
Packit 51d0f7
 * This program is distributed in the hope that it will be useful,
Packit 51d0f7
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 51d0f7
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 51d0f7
 * GNU General Public License for more details.
Packit 51d0f7
 *
Packit 51d0f7
 * You should have received a copy of the GNU General Public License
Packit 51d0f7
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit 51d0f7
 *
Packit 51d0f7
 */
Packit 51d0f7
Packit 51d0f7
#include <stdlib.h>
Packit 51d0f7
#include <errno.h>
Packit 51d0f7
#include <unistd.h>
Packit 51d0f7
#include <linux/types.h>
Packit 51d0f7
#include <sys/types.h>
Packit 51d0f7
Packit 51d0f7
#ifndef __USE_GNU
Packit 51d0f7
#define __USE_GNU
Packit 51d0f7
#include <sys/socket.h>
Packit 51d0f7
#undef __USE_GNU
Packit 51d0f7
#else
Packit 51d0f7
#include <sys/socket.h>
Packit 51d0f7
#endif
Packit 51d0f7
Packit 51d0f7
#include <libnetlabel.h>
Packit 51d0f7
Packit 51d0f7
#include "netlabel_internal.h"
Packit 51d0f7
Packit 51d0f7
/* Netlink read timeout (in seconds) */
Packit 51d0f7
static uint32_t nlcomm_read_timeout = 10;
Packit 51d0f7
Packit 51d0f7
/*
Packit 51d0f7
 * Helper Functions
Packit 51d0f7
 */
Packit 51d0f7
Packit 51d0f7
/**
Packit 51d0f7
 * Validate a NetLabel handle
Packit 51d0f7
 * @param hndl the NetLabel handle
Packit 51d0f7
 *
Packit 51d0f7
 * Return true if @hndl is valid, false otherwise.
Packit 51d0f7
 *
Packit 51d0f7
 */
Packit 51d0f7
static int nlbl_comm_hndl_valid(struct nlbl_handle *hndl)
Packit 51d0f7
{
Packit 51d0f7
	return (hndl != NULL && hndl->nl_sock != NULL);
Packit 51d0f7
}
Packit 51d0f7
Packit 51d0f7
/*
Packit 51d0f7
 * Control Functions
Packit 51d0f7
 */
Packit 51d0f7
Packit 51d0f7
/**
Packit 51d0f7
 * Set the NetLabel timeout
Packit 51d0f7
 * @param seconds the timeout in seconds
Packit 51d0f7
 *
Packit 51d0f7
 * Set the timeout value used by the NetLabel communications layer.
Packit 51d0f7
 *
Packit 51d0f7
 */
Packit 51d0f7
void nlbl_comm_timeout(uint32_t seconds)
Packit 51d0f7
{
Packit 51d0f7
	nlcomm_read_timeout = seconds;
Packit 51d0f7
}
Packit 51d0f7
Packit 51d0f7
/*
Packit 51d0f7
 * Communication Functions
Packit 51d0f7
 */
Packit 51d0f7
Packit 51d0f7
/**
Packit 51d0f7
 * Create and bind a NetLabel handle
Packit 51d0f7
 *
Packit 51d0f7
 * Create a new NetLabel handle, bind it to the running process, and connect to
Packit 51d0f7
 * the Generic Netlink subsystem.  Returns a pointer to the NetLabel handle
Packit 51d0f7
 * structure.
Packit 51d0f7
 *
Packit 51d0f7
 */
Packit 51d0f7
struct nlbl_handle *nlbl_comm_open(void)
Packit 51d0f7
{
Packit 51d0f7
	struct nlbl_handle *hndl;
Packit 51d0f7
Packit 51d0f7
	/* allocate the handle memory */
Packit 51d0f7
	hndl = calloc(1, sizeof(*hndl));
Packit 51d0f7
	if (hndl == NULL)
Packit 51d0f7
		return NULL;
Packit 51d0f7
Packit 51d0f7
	/* create a new netlink socket */
Packit 51d0f7
	hndl->nl_sock = nl_socket_alloc();
Packit 51d0f7
	if (hndl->nl_sock == NULL)
Packit 51d0f7
		goto open_failure;
Packit 51d0f7
Packit 51d0f7
	/* set the netlink socket properties */
Packit 51d0f7
	nl_socket_set_peer_port(hndl->nl_sock, 0);
Packit 51d0f7
	nl_socket_disable_seq_check(hndl->nl_sock);
Packit 51d0f7
	nl_socket_set_passcred(hndl->nl_sock, 1);
Packit 51d0f7
Packit 51d0f7
	/* connect to the generic netlink subsystem in the kernel */
Packit 51d0f7
	if (nl_connect(hndl->nl_sock, NETLINK_GENERIC) != 0)
Packit 51d0f7
		goto open_failure_handle;
Packit 51d0f7
Packit 51d0f7
	return hndl;
Packit 51d0f7
Packit 51d0f7
open_failure_handle:
Packit 51d0f7
	nl_close(hndl->nl_sock);
Packit 51d0f7
	nl_socket_free(hndl->nl_sock);
Packit 51d0f7
open_failure:
Packit 51d0f7
	free(hndl);
Packit 51d0f7
	return NULL;
Packit 51d0f7
}
Packit 51d0f7
Packit 51d0f7
/**
Packit 51d0f7
 * Close and destroy a NetLabel handle
Packit 51d0f7
 * @param hndl the NetLabel handle
Packit 51d0f7
 *
Packit 51d0f7
 * Closes the given NetLabel socket.  Returns zero on success, negative values
Packit 51d0f7
 * on failure.
Packit 51d0f7
 *
Packit 51d0f7
 */
Packit 51d0f7
int nlbl_comm_close(struct nlbl_handle *hndl)
Packit 51d0f7
{
Packit 51d0f7
	/* sanity checks */
Packit 51d0f7
	if (!nlbl_comm_hndl_valid(hndl))
Packit 51d0f7
		return -EINVAL;
Packit 51d0f7
Packit 51d0f7
	/* close and destroy the socket */
Packit 51d0f7
	nl_close(hndl->nl_sock);
Packit 51d0f7
	nl_socket_free(hndl->nl_sock);
Packit 51d0f7
Packit 51d0f7
	/* free the memory */
Packit 51d0f7
	free(hndl);
Packit 51d0f7
Packit 51d0f7
	return 0;
Packit 51d0f7
}
Packit 51d0f7
Packit 51d0f7
/**
Packit 51d0f7
 * Read a message from a NetLabel handle
Packit 51d0f7
 * @param hndl the NetLabel handle
Packit 51d0f7
 * @param data the message buffer
Packit 51d0f7
 *
Packit 51d0f7
 * Reads a message from the NetLabel handle and stores it the pointer returned
Packit 51d0f7
 * in @msg.  This function allocates space for @msg, making the caller
Packit 51d0f7
 * responsibile for freeing @msg later.  Returns the number of bytes read on
Packit 51d0f7
 * success, zero on EOF, and negative values on failure.
Packit 51d0f7
 *
Packit 51d0f7
 */
Packit 51d0f7
int nlbl_comm_recv_raw(struct nlbl_handle *hndl, unsigned char **data)
Packit 51d0f7
{
Packit 51d0f7
	int rc;
Packit 51d0f7
	struct sockaddr_nl peer_nladdr;
Packit 51d0f7
	struct ucred *creds = NULL;
Packit 51d0f7
	int nl_fd;
Packit 51d0f7
	fd_set read_fds;
Packit 51d0f7
	struct timeval timeout;
Packit 51d0f7
Packit 51d0f7
	/* sanity checks */
Packit 51d0f7
	if (!nlbl_comm_hndl_valid(hndl) || data == NULL)
Packit 51d0f7
		return -EINVAL;
Packit 51d0f7
Packit 51d0f7
	/* we use blocking sockets so do enforce a timeout using select() if
Packit 51d0f7
	 * no data is waiting to be read from the handle */
Packit 51d0f7
	timeout.tv_sec = nlcomm_read_timeout;
Packit 51d0f7
	timeout.tv_usec = 0;
Packit 51d0f7
	nl_fd = nl_socket_get_fd(hndl->nl_sock);
Packit 51d0f7
	FD_ZERO(&read_fds);
Packit 51d0f7
	FD_SET(nl_fd, &read_fds);
Packit 51d0f7
	rc = select(nl_fd + 1, &read_fds, NULL, NULL, &timeout);
Packit 51d0f7
	if (rc < 0)
Packit 51d0f7
		return -errno;
Packit 51d0f7
	else if (rc == 0)
Packit 51d0f7
		return -EAGAIN;
Packit 51d0f7
Packit 51d0f7
	/* perform the read operation */
Packit 51d0f7
	*data = NULL;
Packit 51d0f7
	rc = nl_recv(hndl->nl_sock, &peer_nladdr, data, &creds);
Packit 51d0f7
	if (rc < 0)
Packit 51d0f7
		return rc;
Packit 51d0f7
Packit 51d0f7
	/* if we are setup to receive credentials, only accept messages from
Packit 51d0f7
	 * the kernel (ignore all others and send an -EAGAIN) */
Packit 51d0f7
	if (creds != NULL && creds->pid != 0) {
Packit 51d0f7
		rc = -EAGAIN;
Packit 51d0f7
		goto recv_raw_failure;
Packit 51d0f7
	}
Packit 51d0f7
Packit 51d0f7
	return rc;
Packit 51d0f7
Packit 51d0f7
recv_raw_failure:
Packit 51d0f7
	if (*data != NULL) {
Packit 51d0f7
		free(*data);
Packit 51d0f7
		*data = NULL;
Packit 51d0f7
	}
Packit 51d0f7
	return rc;
Packit 51d0f7
}
Packit 51d0f7
Packit 51d0f7
/**
Packit 51d0f7
 * Read a message from a NetLabel handle
Packit 51d0f7
 * @param hndl the NetLabel handle
Packit 51d0f7
 * @param msg the message buffer
Packit 51d0f7
 *
Packit 51d0f7
 * Reads a message from the NetLabel handle and stores it the pointer returned
Packit 51d0f7
 * in @msg.  This function allocates space for @msg, making the caller
Packit 51d0f7
 * responsibile for freeing @msg later.  Returns the number of bytes read on
Packit 51d0f7
 * success, zero on EOF, and negative values on failure.
Packit 51d0f7
 *
Packit 51d0f7
 */
Packit 51d0f7
int nlbl_comm_recv(struct nlbl_handle *hndl, nlbl_msg **msg)
Packit 51d0f7
{
Packit 51d0f7
	int rc;
Packit 51d0f7
	unsigned char *data = NULL;
Packit 51d0f7
	struct nlmsghdr *nl_hdr;
Packit 51d0f7
Packit 51d0f7
	/* perform the raw read operation */
Packit 51d0f7
	rc = nlbl_comm_recv_raw(hndl, &data);
Packit 51d0f7
	if (rc < 0)
Packit 51d0f7
		return rc;
Packit 51d0f7
	nl_hdr = (struct nlmsghdr *)data;
Packit 51d0f7
Packit 51d0f7
	/* make sure the received buffer is the correct length */
Packit 51d0f7
	if (!nlmsg_ok(nl_hdr, rc)) {
Packit 51d0f7
		rc = -EBADMSG;
Packit 51d0f7
		goto recv_failure;
Packit 51d0f7
	}
Packit 51d0f7
Packit 51d0f7
	/* check to see if this is a netlink control message we don't care
Packit 51d0f7
	 * about */
Packit 51d0f7
	if (nl_hdr->nlmsg_type == NLMSG_NOOP ||
Packit 51d0f7
	    nl_hdr->nlmsg_type == NLMSG_OVERRUN) {
Packit 51d0f7
		rc = -EBADMSG;
Packit 51d0f7
		goto recv_failure;
Packit 51d0f7
	}
Packit 51d0f7
Packit 51d0f7
	/* convert the received buffer into a nlbl_msg */
Packit 51d0f7
	*msg = nlmsg_convert((struct nlmsghdr *)data);
Packit 51d0f7
	if (*msg == NULL) {
Packit 51d0f7
		rc = -EBADMSG;
Packit 51d0f7
		goto recv_failure;
Packit 51d0f7
	}
Packit 51d0f7
Packit 51d0f7
	return rc;
Packit 51d0f7
Packit 51d0f7
recv_failure:
Packit 51d0f7
	if (data != NULL)
Packit 51d0f7
		free(data);
Packit 51d0f7
	return rc;
Packit 51d0f7
}
Packit 51d0f7
Packit 51d0f7
/**
Packit 51d0f7
 * Write a message to a NetLabel handle
Packit 51d0f7
 * @param hndl the NetLabel handle
Packit 51d0f7
 * @param msg the message
Packit 51d0f7
 *
Packit 51d0f7
 * Write the message in @msg to the NetLabel handle @hndl.  Returns the number
Packit 51d0f7
 * of bytes written on success, or negative values on failure.
Packit 51d0f7
 *
Packit 51d0f7
 */
Packit 51d0f7
int nlbl_comm_send(struct nlbl_handle *hndl, nlbl_msg *msg)
Packit 51d0f7
{
Packit 51d0f7
	struct nlmsghdr *nl_hdr;
Packit 51d0f7
Packit 51d0f7
	/* sanity checks */
Packit 51d0f7
	if (!nlbl_comm_hndl_valid(hndl) || msg == NULL)
Packit 51d0f7
		return -EINVAL;
Packit 51d0f7
Packit 51d0f7
	/* request a netlink ack message */
Packit 51d0f7
	nl_hdr = nlbl_msg_nlhdr(msg);
Packit 51d0f7
	if (nl_hdr == NULL)
Packit 51d0f7
		return -EBADMSG;
Packit 51d0f7
	nl_hdr->nlmsg_flags |= NLM_F_ACK;
Packit 51d0f7
Packit 51d0f7
	/* send the message */
Packit 51d0f7
	return nl_send_auto(hndl->nl_sock, msg);
Packit 51d0f7
}