2 * Copyright 2004, 2005, 2009, 2013 Red Hat Inc., Durham, North Carolina.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 * Steve Grubb <sgrubb@redhat.com>
21 * Rickard E. (Rik) Faith <faith@redhat.com>
35 #define NETLINK_AUDIT 9
38 static int adjust_reply(struct audit_reply *rep, int len);
39 static int check_ack(int fd, int seq);
42 * This function opens a connection to the kernel's audit
43 * subsystem. You must be root for the call to succeed. On error,
44 * a negative value is returned. On success, the file descriptor is
45 * returned - which can be 0 or higher.
50 int fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_AUDIT);
54 if (errno == EINVAL || errno == EPROTONOSUPPORT ||
55 errno == EAFNOSUPPORT)
57 "Error - audit support not in kernel");
60 "Error opening audit netlink socket (%s)",
65 if (fcntl(fd, F_SETFD, FD_CLOEXEC) == -1) {
69 "Error setting audit netlink socket CLOEXEC flag (%s)",
78 void audit_close(int fd)
86 * This function returns -1 on error, 0 if error response received,
87 * and > 0 if packet OK.
89 int audit_get_reply(int fd, struct audit_reply *rep, reply_t block, int peek)
92 struct sockaddr_nl nladdr;
93 socklen_t nladdrlen = sizeof(nladdr);
98 if (block == GET_REPLY_NONBLOCKING)
102 len = recvfrom(fd, &rep->msg, sizeof(rep->msg), block|peek,
103 (struct sockaddr*)&nladdr, &nladdrlen);
108 if (errno != EAGAIN) {
109 int saved_errno = errno;
111 "Error receiving audit netlink packet (%s)",
117 if (nladdrlen != sizeof(nladdr)) {
119 "Bad address size reading audit netlink socket");
124 "Spoofed packet received on audit netlink socket");
128 len = adjust_reply(rep, len);
133 hidden_def(audit_get_reply)
137 * This function returns 0 on error and len on success.
139 static int adjust_reply(struct audit_reply *rep, int len)
141 rep->type = rep->msg.nlh.nlmsg_type;
142 rep->len = rep->msg.nlh.nlmsg_len;
143 rep->nlh = &rep->msg.nlh;
145 rep->ruledata = NULL;
149 rep->signal_info = NULL;
151 #if HAVE_DECL_AUDIT_FEATURE_VERSION
152 rep->features = NULL;
154 if (!NLMSG_OK(rep->nlh, (unsigned int)len)) {
155 if (len == sizeof(rep->msg)) {
157 "Netlink event from kernel is too big");
161 "Netlink message from kernel was not OK");
167 /* Next we'll set the data structure to point to msg.data. This is
168 * to avoid having to use casts later. */
171 rep->error = NLMSG_DATA(rep->nlh);
174 rep->status = NLMSG_DATA(rep->nlh);
176 #if HAVE_DECL_AUDIT_FEATURE_VERSION
177 case AUDIT_GET_FEATURE:
178 rep->features = NLMSG_DATA(rep->nlh);
181 case AUDIT_LIST_RULES:
182 rep->ruledata = NLMSG_DATA(rep->nlh);
187 case AUDIT_FIRST_USER_MSG...AUDIT_LAST_USER_MSG:
188 case AUDIT_FIRST_USER_MSG2...AUDIT_LAST_USER_MSG2:
189 case AUDIT_FIRST_EVENT...AUDIT_INTEGRITY_LAST_MSG:
190 rep->message = NLMSG_DATA(rep->nlh);
192 case AUDIT_SIGNAL_INFO:
193 rep->signal_info = NLMSG_DATA(rep->nlh);
201 * Return values: success: positive non-zero sequence number
205 int audit_send(int fd, int type, const void *data, unsigned int size)
207 static int sequence = 0;
208 struct audit_message req;
210 struct sockaddr_nl addr;
212 /* Due to user space library callbacks, there's a chance that
213 a -1 for the fd could be passed. Just check for and handle it. */
219 if (NLMSG_SPACE(size) > MAX_AUDIT_MESSAGE_LENGTH) {
227 memset(&req, 0, sizeof(req));
228 req.nlh.nlmsg_len = NLMSG_SPACE(size);
229 req.nlh.nlmsg_type = type;
230 req.nlh.nlmsg_flags = NLM_F_REQUEST|NLM_F_ACK;
231 req.nlh.nlmsg_seq = sequence;
233 memcpy(NLMSG_DATA(&req.nlh), data, size);
234 memset(&addr, 0, sizeof(addr));
235 addr.nl_family = AF_NETLINK;
240 retval = sendto(fd, &req, req.nlh.nlmsg_len, 0,
241 (struct sockaddr*)&addr, sizeof(addr));
242 } while (retval < 0 && errno == EINTR);
243 if (retval == (int)req.nlh.nlmsg_len) {
244 if ((retval = check_ack(fd, sequence)) == 0)
254 hidden_def(audit_send)
257 * This function will take a peek into the next packet and see if there's
258 * an error. If so, the error is returned and its non-zero. Otherwise a
259 * zero is returned indicating that we don't know of any problems.
261 static int check_ack(int fd, int seq)
263 int rc, retries = 80;
264 struct audit_reply rep;
265 struct pollfd pfd[1];
269 pfd[0].events = POLLIN;
271 rc = poll(pfd, 1, 500); /* .5 second */
272 } while (rc < 0 && errno == EINTR);
274 /* We don't look at rc from above as it doesn't matter. We are
275 * going to try to read nonblocking just in case packet shows up. */
277 /* NOTE: whatever is returned is treated as the errno */
278 rc = audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, MSG_PEEK);
279 if (rc == -EAGAIN && retries) {
285 return -EINVAL; /* This can't happen anymore */
286 else if (rc > 0 && rep.type == NLMSG_ERROR) {
287 int error = rep.error->error;
288 /* Eat the message */
289 (void)audit_get_reply(fd, &rep, GET_REPLY_NONBLOCKING, 0);
291 /* NLMSG_ERROR can indicate success, only report nonzero */