-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathauditpipe.cpp
119 lines (98 loc) · 3.31 KB
/
auditpipe.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include <bsm/libbsm.h>
#include <cstdio>
#include <cstdlib>
#include <fcntl.h>
#include <security/audit/audit_ioctl.h>
#include <signal.h>
#include <sys/errno.h>
#include <sys/ioctl.h>
#include <unistd.h>
static auto config_failure() {
perror("error: could not configure /dev/auditpipe");
return EXIT_FAILURE;
}
static bool keep_running = true;
static void stop_running(int _signal) { keep_running = false; }
#define break_or_fail(MESSAGE) \
if (errno == EINTR) { \
break; \
} \
perror(MESSAGE); \
return EXIT_FAILURE;
int main(int argc, char **argv) {
if (argc != 2 || strcmp(argv[1], "-h") == 0) {
fprintf(stderr,
"usage:\n"
"\t%s <event-classes> | praudit\n"
"\t%s <event-classes> > /path/to/log\n",
argv[0], argv[0]);
return EXIT_FAILURE;
}
const auto event_classes = argv[1];
au_mask_t masks;
if (getauditflagsbin(event_classes, &masks)) {
perror("error: unknown event class");
return EXIT_FAILURE;
}
if (geteuid() != 0) {
// Re-exec with sudo.
const char *cmd[] = {"sudo", argv[0], argv[1], nullptr};
execvp("sudo", (char **)cmd);
}
if (isatty(STDOUT_FILENO)) {
fprintf(stderr, "error: cannot print to stdout, try piping to praudit\n");
return EXIT_FAILURE;
}
auto pipe = open("/dev/auditpipe", O_RDONLY);
if (not pipe) {
perror("error: could not open /dev/auditpipe");
return EXIT_FAILURE;
}
//
// See man auditpipe for details on these auditpipe ioctls.
int mode = AUDITPIPE_PRESELECT_MODE_LOCAL;
if (ioctl(pipe, AUDITPIPE_SET_PRESELECT_MODE, &mode)) {
return config_failure();
}
// Increase the event queue to the largest maximum size.
u_int max_qlimit;
if (ioctl(pipe, AUDITPIPE_GET_QLIMIT_MAX, &max_qlimit) ||
ioctl(pipe, AUDITPIPE_SET_QLIMIT, &max_qlimit)) {
return config_failure();
}
if (ioctl(pipe, AUDITPIPE_SET_PRESELECT_FLAGS, &masks)) {
return config_failure();
}
u_int max_audit_record_size;
if (ioctl(pipe, AUDITPIPE_GET_MAXAUDITDATA, &max_audit_record_size)) {
return config_failure();
}
struct sigaction act;
act.sa_handler = stop_running;
sigaction(SIGINT, &act, nullptr);
auto buffer_size = max_audit_record_size * max_qlimit;
auto buffer = new char[buffer_size];
while (keep_running) {
auto read_size = read(pipe, buffer, buffer_size);
if (read_size == -1) {
break_or_fail("error: failed to read from /dev/auditpipe");
}
auto write_size = write(STDOUT_FILENO, buffer, read_size);
if (write_size == -1) {
break_or_fail("error: failed to write to stdout");
}
if (write_size != read_size) {
fprintf(stderr, "error: incomplete write to stdout");
return EXIT_FAILURE;
}
}
delete[] buffer;
u_int64_t drop_count;
if (ioctl(pipe, AUDITPIPE_GET_DROPS, &drop_count) == 0) {
if (drop_count > 0) {
// Use \n prefix because the interrupt has printed a bare "^C".
fprintf(stderr, "\nwarning: %llu dropped audit events\n", drop_count);
}
}
return EXIT_SUCCESS;
}