1// SPDX-License-Identifier: GPL-2.0 2 3#define _GNU_SOURCE 4#include <errno.h> 5#include <fcntl.h> 6#include <poll.h> 7#include <signal.h> 8#include <stdint.h> 9#include <stdio.h> 10#include <stdlib.h> 11#include <string.h> 12#include <sys/socket.h> 13#include <unistd.h> 14#include <linux/audit.h> 15#include <linux/netlink.h> 16 17static int fd; 18 19#define MAX_AUDIT_MESSAGE_LENGTH 8970 20struct audit_message { 21 struct nlmsghdr nlh; 22 union { 23 struct audit_status s; 24 char data[MAX_AUDIT_MESSAGE_LENGTH]; 25 } u; 26}; 27 28int audit_recv(int fd, struct audit_message *rep) 29{ 30 struct sockaddr_nl addr; 31 socklen_t addrlen = sizeof(addr); 32 int ret; 33 34 do { 35 ret = recvfrom(fd, rep, sizeof(*rep), 0, 36 (struct sockaddr *)&addr, &addrlen); 37 } while (ret < 0 && errno == EINTR); 38 39 if (ret < 0 || 40 addrlen != sizeof(addr) || 41 addr.nl_pid != 0 || 42 rep->nlh.nlmsg_type == NLMSG_ERROR) /* short-cut for now */ 43 return -1; 44 45 return ret; 46} 47 48int audit_send(int fd, uint16_t type, uint32_t key, uint32_t val) 49{ 50 static int seq = 0; 51 struct audit_message msg = { 52 .nlh = { 53 .nlmsg_len = NLMSG_SPACE(sizeof(msg.u.s)), 54 .nlmsg_type = type, 55 .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK, 56 .nlmsg_seq = ++seq, 57 }, 58 .u.s = { 59 .mask = key, 60 .enabled = key == AUDIT_STATUS_ENABLED ? val : 0, 61 .pid = key == AUDIT_STATUS_PID ? val : 0, 62 } 63 }; 64 struct sockaddr_nl addr = { 65 .nl_family = AF_NETLINK, 66 }; 67 int ret; 68 69 do { 70 ret = sendto(fd, &msg, msg.nlh.nlmsg_len, 0, 71 (struct sockaddr *)&addr, sizeof(addr)); 72 } while (ret < 0 && errno == EINTR); 73 74 if (ret != (int)msg.nlh.nlmsg_len) 75 return -1; 76 return 0; 77} 78 79int audit_set(int fd, uint32_t key, uint32_t val) 80{ 81 struct audit_message rep = { 0 }; 82 int ret; 83 84 ret = audit_send(fd, AUDIT_SET, key, val); 85 if (ret) 86 return ret; 87 88 ret = audit_recv(fd, &rep); 89 if (ret < 0) 90 return ret; 91 return 0; 92} 93 94int readlog(int fd) 95{ 96 struct audit_message rep = { 0 }; 97 int ret = audit_recv(fd, &rep); 98 const char *sep = ""; 99 char *k, *v; 100 101 if (ret < 0) 102 return ret; 103 104 if (rep.nlh.nlmsg_type != AUDIT_NETFILTER_CFG) 105 return 0; 106 107 /* skip the initial "audit(...): " part */ 108 strtok(rep.u.data, " "); 109 110 while ((k = strtok(NULL, "="))) { 111 v = strtok(NULL, " "); 112 113 /* these vary and/or are uninteresting, ignore */ 114 if (!strcmp(k, "pid") || 115 !strcmp(k, "comm") || 116 !strcmp(k, "subj")) 117 continue; 118 119 /* strip the varying sequence number */ 120 if (!strcmp(k, "table")) 121 *strchrnul(v, ':') = '\0'; 122 123 printf("%s%s=%s", sep, k, v); 124 sep = " "; 125 } 126 if (*sep) { 127 printf("\n"); 128 fflush(stdout); 129 } 130 return 0; 131} 132 133void cleanup(int sig) 134{ 135 audit_set(fd, AUDIT_STATUS_ENABLED, 0); 136 close(fd); 137 if (sig) 138 exit(0); 139} 140 141int main(int argc, char **argv) 142{ 143 struct sigaction act = { 144 .sa_handler = cleanup, 145 }; 146 147 fd = socket(PF_NETLINK, SOCK_RAW, NETLINK_AUDIT); 148 if (fd < 0) { 149 perror("Can't open netlink socket"); 150 return -1; 151 } 152 153 if (sigaction(SIGTERM, &act, NULL) < 0 || 154 sigaction(SIGINT, &act, NULL) < 0) { 155 perror("Can't set signal handler"); 156 close(fd); 157 return -1; 158 } 159 160 audit_set(fd, AUDIT_STATUS_ENABLED, 1); 161 audit_set(fd, AUDIT_STATUS_PID, getpid()); 162 163 while (1) 164 readlog(fd); 165} 166