Skip to content

Instantly share code, notes, and snippets.

@AALEKH
Created September 18, 2014 12:00
Show Gist options
  • Save AALEKH/8c7994dfdd945060be3b to your computer and use it in GitHub Desktop.
Save AALEKH/8c7994dfdd945060be3b to your computer and use it in GitHub Desktop.
KDIR := /lib/modules/$(shell uname -r)/build
obj-m += test.o
all:
$(MAKE) -C $(KDIR) SUBDIRS=$(PWD) modules
clean:
rm -rf *.o *.ko *.mod.* *.cmd .module* modules* Module* .*.cmd .tmp*
make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean
/* netlink.c --
* Copyright 2004, 2005, 2009, 2013 Red Hat Inc., Durham, North Carolina.
* All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Authors:
* Steve Grubb <sgrubb@redhat.com>
* Rickard E. (Rik) Faith <faith@redhat.com>
*/
#include "config.h"
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <sys/poll.h>
#include "libaudit.h"
#include "private.h"
#ifndef NETLINK_AUDIT
#define NETLINK_AUDIT 9
#endif
static int adjust_reply(struct audit_reply *rep, int len);
static int check_ack(int fd, int seq);
/*
* This function opens a connection to the kernel's audit
* subsystem. You must be root for the call to succeed. On error,
* a negative value is returned. On success, the file descriptor is
* returned - which can be 0 or higher.
*/
int audit_open(void)
{
int saved_errno;
int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_AUDIT);
if (fd < 0) {
saved_errno = errno;
if (errno == EINVAL || errno == EPROTONOSUPPORT ||
errno == EAFNOSUPPORT)
audit_msg(LOG_ERR,
"Error - audit support not in kernel");
else
audit_msg(LOG_ERR,
"Error opening audit netlink socket (%s)",
strerror(errno));
errno = saved_errno;
return fd;
}
if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
saved_errno = errno;
close(fd);
audit_msg(LOG_ERR,
"Error setting audit netlink socket CLOEXEC flag (%s)",
strerror(errno));
errno = saved_errno;
return -1;
}
return fd;
}
void audit_close(int fd)
{
if (fd >= 0)
close(fd);
}
/*
* This function returns -1 on error, 0 if error response received,
* and > 0 if packet OK.
*/
int audit_get_reply(int fd, struct audit_reply *rep, reply_t block, int peek)
{
int len;
struct sockaddr_nl nladdr;
socklen_t nladdrlen = sizeof(nladdr);
if (fd < 0)
return -EBADF;
if (block == GET_REPLY_NONBLOCKING)
block = MSG_DONTWAIT;
retry:
len = recvfrom(fd, &rep->msg, sizeof(rep->msg), block|peek,
(struct sockaddr*)&nladdr, &nladdrlen);
if (len < 0) {
if (errno == EINTR)
goto retry;
if (errno != EAGAIN) {
int saved_errno = errno;
audit_msg(LOG_ERR,
"Error receiving audit netlink packet (%s)",
strerror(errno));
errno = saved_errno;
}
return -errno;
}
if (nladdrlen != sizeof(nladdr)) {
audit_msg(LOG_ERR,
"Bad address size reading audit netlink socket");
return -EPROTO;
}
if (nladdr.nl_pid) {
audit_msg(LOG_ERR,
"Spoofed packet received on audit netlink socket");
return -EINVAL;
}
len = adjust_reply(rep, len);
if (len == 0)
len = -errno;
return len;
}
hidden_def(audit_get_reply)
/*
* This function returns 0 on error and len on success.
*/
static int adjust_reply(struct audit_reply *rep, int len)
{
rep->type = rep->msg.nlh.nlmsg_type;
rep->len = rep->msg.nlh.nlmsg_len;
rep->nlh = &rep->msg.nlh;
rep->status = NULL;
rep->ruledata = NULL;
rep->login = NULL;
rep->message = NULL;
rep->error = NULL;
rep->signal_info = NULL;
rep->conf = NULL;
if (!NLMSG_OK(rep->nlh, (unsigned int)len)) {
if (len == sizeof(rep->msg)) {
audit_msg(LOG_ERR,
"Netlink event from kernel is too big");
errno = EFBIG;
} else {
audit_msg(LOG_ERR,
"Netlink message from kernel was not OK");
errno = EBADE;
}
return 0;
}
/* Next we'll set the data structure to point to msg.data. This is
* to avoid having to use casts later. */
switch (rep->type) {
case NLMSG_ERROR:
rep->error = NLMSG_DATA(rep->nlh);
break;
case AUDIT_GET:
rep->status = NLMSG_DATA(rep->nlh);
break;
case AUDIT_LIST_RULES:
rep->ruledata = NLMSG_DATA(rep->nlh);
break;
case AUDIT_USER:
case AUDIT_LOGIN:
case AUDIT_KERNEL:
case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2:
case AUDIT_FIRST_EVENT...AUDIT_INTEGRITY_LAST_MSG:
rep->message = NLMSG_DATA(rep->nlh);
break;
case AUDIT_SIGNAL_INFO:
rep->signal_info = NLMSG_DATA(rep->nlh);
break;
}
return len;
}
/*
* Return values: success: positive non-zero sequence number
* error: -errno
* short: 0
*/
int audit_send(int fd, int type, const void *data, unsigned int size)
{
static int sequence = 0;
struct audit_message req;
int retval;
struct sockaddr_nl addr;
/* Due to user space library callbacks, there's a chance that
a -1 for the fd could be passed. Just check for and handle it. */
if (fd < 0) {
errno = EBADF;
return -errno;
}
if (NLMSG_SPACE(size) > MAX_AUDIT_MESSAGE_LENGTH) {
errno = EINVAL;
return -errno;
}
if (++sequence < 0)
sequence = 1;
memset(&req, 0, sizeof(req));
req.nlh.nlmsg_len = NLMSG_SPACE(size);
req.nlh.nlmsg_type = type;
req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
req.nlh.nlmsg_seq = sequence;
if (size && data)
memcpy(NLMSG_DATA(&req.nlh), data, size);
memset(&addr, 0, sizeof(addr));
addr.nl_family = AF_NETLINK;
addr.nl_pid = 0;
addr.nl_groups = 0;
do {
retval = sendto(fd, &req, req.nlh.nlmsg_len, 0,
(struct sockaddr*)&addr, sizeof(addr));
} while (retval < 0 && errno == EINTR);
if (retval == (int)req.nlh.nlmsg_len) {
if ((retval = check_ack(fd, sequence)) == 0)
return sequence;
else
return retval;
}
if (retval < 0)
return -errno;
return 0;
}
hidden_def(audit_send)
/*
* This function will take a peek into the next packet and see if there's
* an error. If so, the error is returned and its non-zero. Otherwise a
* zero is returned indicating that we don't know of any problems.
*/
static int check_ack(int fd, int seq)
{
int rc, retries = 80;
struct audit_reply rep;
struct pollfd pfd[1];
retry:
pfd[0].fd = fd;
pfd[0].events = POLLIN;
do {
rc = poll(pfd, 1, 500); /* .5 second */
} while (rc < 0 && errno == EINTR);
/* We don't look at rc from above as it doesn't matter. We are
* going to try to read nonblocking just in case packet shows up. */
/* NOTE: whatever is returned is treated as the errno */
rc = audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, MSG_PEEK);
if (rc == -EAGAIN && retries) {
retries--;
goto retry;
} else if (rc < 0)
return rc;
else if (rc == 0)
return -EINVAL; /* This can't happen anymore */
else if (rc > 0 && rep.type == NLMSG_ERROR) {
int error = rep.error->error;
/* Eat the message */
(void)audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
/* NLMSG_ERROR can indicate success, only report nonzero */
if (error) {
errno = -error;
return error;
}
}
return 0;
}
int main()
{
/* code */
int connection;
connection = audit_open();
printf("Connection: %i\n",connection );
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment