Merge tag 'powerpc-6.6-6' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[platform/kernel/linux-starfive.git] / tools / testing / selftests / netfilter / audit_logread.c
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
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
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
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
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
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
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 }