|
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 |
}
|