Skip to content

Commit c5ce7c3

Browse files
committed
Add libauplugin example
This adds an example that performs exactly the same as the older example. This shows how to setup a plugin.
1 parent fdd4538 commit c5ce7c3

File tree

4 files changed

+225
-2
lines changed

4 files changed

+225
-2
lines changed

Makefile.am

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,14 @@ SUBDIRS = common lib auparse audisp auplugin audisp/plugins src/libev \
2626
src tools bindings init.d m4 docs rules
2727
EXTRA_DIST = ChangeLog AUTHORS NEWS README.md INSTALL \
2828
audit.spec COPYING COPYING.LIB \
29-
contrib/avc_snap contrib/plugin/Makefile \
29+
contrib/avc_snap \
30+
contrib/plugin/Makefile \
3031
contrib/plugin/audisp-example.c \
31-
contrib/plugin/audisp-example.conf
32+
contrib/plugin/audisp-example.conf \
33+
contrib/libauplugin/Makefile \
34+
contrib/libauplugin/auplugin-example.c \
35+
contrib/libauplugin/auplugin-example.conf
36+
3237
CONFIG_CLEAN_FILES = debug*.list config/*
3338

3439
clean-generic:

contrib/libauplugin/Makefile

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
CFLAGS=-g -W -Wall -Wundef
2+
LIBS= -lauplugin -lauparse -laudit
3+
all:
4+
gcc $(CFLAGS) auplugin-example.c -o auplugin-example $(LIBS)
5+
6+
clean:
7+
rm -f auplugin-example *.o
Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
/* auplugin-example.c --
2+
* Copyright 2025 Red Hat Inc.
3+
* All Rights Reserved.
4+
*
5+
* This program is free software; you can redistribute it and/or modify
6+
* it under the terms of the GNU General Public License as published by
7+
* the Free Software Foundation; either version 2 of the License, or
8+
* (at your option) any later version.
9+
*
10+
* This program 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
13+
* GNU General Public License for more details.
14+
*
15+
* You should have received a copy of the GNU General Public License
16+
* along with this program; if not, write to the Free Software
17+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA
18+
*
19+
* Authors:
20+
* Steve Grubb <[email protected]>
21+
*
22+
* This is a sample program showing how to write an audisp plugin using
23+
* the libauplugin helper library. It is functionally equivalent to the
24+
* contrib/plugin/audisp-example.c program but avoids manual queue and
25+
* event management by delegating that work to libauplugin.
26+
*
27+
* To test with a file of raw audit records, generate the file with:
28+
* ausearch --start today --raw > test.log
29+
* and then run:
30+
* cat test.log | ./auplugin-example
31+
*/
32+
33+
#define _GNU_SOURCE
34+
#include <stdio.h>
35+
#include <signal.h>
36+
#include <unistd.h>
37+
#include <auplugin.h>
38+
39+
/* Global Data */
40+
static volatile sig_atomic_t stop = 0;
41+
static volatile sig_atomic_t hup = 0;
42+
43+
/* Local declarations */
44+
static void handle_event(auparse_state_t *au,
45+
auparse_cb_event_t cb_event_type,
46+
void *user_data __attribute__((unused)));
47+
48+
/*
49+
* SIGTERM handler
50+
*
51+
* Only honor the signal if it comes from the parent process so that other
52+
* tasks (for example systemctl) cannot make the plugin exit without the
53+
* dispatcher in agreement. The handler also stops the libauplugin worker
54+
* thread so that auplugin_event_feed returns.
55+
*/
56+
static void term_handler(int sig __attribute__((unused)), siginfo_t *info,
57+
void *ucontext __attribute__((unused)))
58+
{
59+
if (info && info->si_pid != getppid())
60+
return;
61+
stop = 1;
62+
auplugin_stop();
63+
}
64+
65+
/*
66+
* SIGHUP handler: request configuration reload.
67+
*/
68+
static void hup_handler(int sig __attribute__((unused)))
69+
{
70+
hup = 1;
71+
}
72+
73+
static void reload_config(void)
74+
{
75+
hup = 0;
76+
/*
77+
* Add your code here that re-reads the config file and changes
78+
* how your plugin works.
79+
*/
80+
}
81+
82+
int main(int argc, char *argv[])
83+
{
84+
struct sigaction sa;
85+
86+
/* Register signal handlers expected by auditd plugins */
87+
sa.sa_flags = 0;
88+
sigemptyset(&sa.sa_mask);
89+
sa.sa_handler = hup_handler;
90+
sigaction(SIGHUP, &sa, NULL);
91+
sa.sa_sigaction = term_handler;
92+
sa.sa_flags = SA_SIGINFO;
93+
sigaction(SIGTERM, &sa, NULL);
94+
95+
/*
96+
* Initialize libauplugin.
97+
* - inbound_fd: 0 (read events from stdin)
98+
* - queue_size: 128 events kept in memory
99+
* - q_flags: AUPLUGIN_Q_IN_MEMORY for an in-memory queue
100+
* - path: unused here
101+
*/
102+
if (auplugin_init(0, 128, AUPLUGIN_Q_IN_MEMORY, NULL)) {
103+
fprintf(stderr, "failed to init auplugin\n");
104+
return 1;
105+
}
106+
107+
/*
108+
* Feed events to libauparse. The callback will be invoked for each
109+
* complete event. The timer flushes aged events every second.
110+
*/
111+
if (auplugin_event_feed(handle_event, 1, NULL)) {
112+
fprintf(stderr, "failed to start event feed\n");
113+
return 1;
114+
}
115+
116+
if (stop)
117+
printf("audisp-example-auplugin is exiting on stop request\n");
118+
else
119+
printf("audisp-example-auplugin is exiting on stdin EOF\n");
120+
121+
return 0;
122+
}
123+
124+
/* Helper: dump a whole event by iterating over records */
125+
static void dump_whole_event(auparse_state_t *au)
126+
{
127+
auparse_first_record(au);
128+
do {
129+
printf("%s\n", auparse_get_record_text(au));
130+
} while (auparse_next_record(au) > 0);
131+
printf("\n");
132+
}
133+
134+
/* Helper: dump a single record's text */
135+
static void dump_whole_record(auparse_state_t *au)
136+
{
137+
printf("%s: %s\n", audit_msg_type_to_name(auparse_get_type(au)),
138+
auparse_get_record_text(au));
139+
printf("\n");
140+
}
141+
142+
/* Helper: iterate through the fields of a record and print details */
143+
static void dump_fields_of_record(auparse_state_t *au)
144+
{
145+
printf("record type %d(%s) has %d fields\n", auparse_get_type(au),
146+
audit_msg_type_to_name(auparse_get_type(au)),
147+
auparse_get_num_fields(au));
148+
149+
printf("line=%d file=%s\n", auparse_get_line_number(au),
150+
auparse_get_filename(au) ? auparse_get_filename(au) : "stdin");
151+
152+
const au_event_t *e = auparse_get_timestamp(au);
153+
if (e == NULL) {
154+
printf("Error getting timestamp - aborting\n");
155+
return;
156+
}
157+
/* e->sec may be treated as time_t for human readable output */
158+
printf("event time: %u.%u:%lu, host=%s\n", (unsigned)e->sec,
159+
e->milli, e->serial, e->host ? e->host : "?");
160+
auparse_first_field(au);
161+
162+
do {
163+
printf("field: %s=%s (%s)\n",
164+
auparse_get_field_name(au),
165+
auparse_get_field_str(au),
166+
auparse_interpret_field(au));
167+
} while (auparse_next_field(au) > 0);
168+
printf("\n");
169+
}
170+
171+
/*
172+
* Callback from auplugin_event_feed. We receive a completed event and can
173+
* inspect it using libauparse APIs. This is where plugin specific logic
174+
* would normally be implemented.
175+
*/
176+
static void handle_event(auparse_state_t *au,
177+
auparse_cb_event_t cb_event_type, void *user_data)
178+
{
179+
int type, num = 0;
180+
181+
/* Process any pending signal requests */
182+
if (hup)
183+
reload_config();
184+
185+
/* Iterate over records in the event looking for ones to process */
186+
while (auparse_goto_record_num(au, num) > 0) {
187+
type = auparse_get_type(au);
188+
switch (type) {
189+
case AUDIT_AVC:
190+
dump_fields_of_record(au);
191+
break;
192+
case AUDIT_SYSCALL:
193+
dump_whole_record(au);
194+
break;
195+
case AUDIT_MAC_STATUS:
196+
dump_whole_event(au);
197+
break;
198+
default:
199+
break;
200+
}
201+
num++;
202+
}
203+
}
204+
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Example plugin using libauplugin
2+
active = no
3+
direction = out
4+
path = /sbin/auplugin-example
5+
type = always
6+
args = 1
7+
format = string

0 commit comments

Comments
 (0)