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
17 static int fd;
18
19 #define MAX_AUDIT_MESSAGE_LENGTH 8970
20 struct audit_message {
21 struct nlmsghdr nlh;
22 union {
23 struct audit_status s;
24 char data[MAX_AUDIT_MESSAGE_LENGTH];
25 } u;
26 };
27
audit_recv(int fd,struct audit_message * rep)28 int 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
audit_send(int fd,uint16_t type,uint32_t key,uint32_t val)48 int 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
audit_set(int fd,uint32_t key,uint32_t val)79 int 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
readlog(int fd)94 int 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
cleanup(int sig)133 void cleanup(int sig)
134 {
135 audit_set(fd, AUDIT_STATUS_ENABLED, 0);
136 close(fd);
137 if (sig)
138 exit(0);
139 }
140
main(int argc,char ** argv)141 int 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