/* * audit-multicast-listen.c * Copyright (2013, 104) Red Hat, Inc. * Richard Guy Briggs * * This program is a test implementation of an audit multicast read-only socket * for receiving logs with the CAP_AUDIT_READ capability. * * gcc -o audit-multicast-listen -Wall -W -lcap-ng audit-multicast-listen.c * */ #include #include #include #include #include #include #include #include /* select */ #include #include #include #define HAVE_LIBCAP_NG #ifdef HAVE_LIBCAP_NG #include #endif #ifndef CAP_AUDIT_READ #define CAP_AUDIT_READ 37 #endif int main(int argc, char *argv[]) { int socket_fd; const struct sockaddr_nl sanl = { .nl_family = AF_NETLINK, .nl_pid = 0, .nl_groups = 1, }; int ret; char nlh[4096]; struct iovec iov = { nlh, sizeof(nlh) }; struct msghdr msg = { .msg_name = (void *)&sanl, .msg_namelen = sizeof(sanl), .msg_iov = &iov, .msg_iovlen = 1, .msg_control = NULL, .msg_controllen = 0, .msg_flags = 0, }; fd_set rfds; argc = argc; /* shut up compiler */ #ifdef HAVE_LIBCAP_NG /* Drop capabilities */ capng_clear(CAPNG_SELECT_BOTH); capng_update(CAPNG_ADD, CAPNG_EFFECTIVE|CAPNG_PERMITTED|CAPNG_BOUNDING_SET, CAP_AUDIT_READ); capng_apply(CAPNG_SELECT_BOTH); #endif socket_fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_AUDIT); if (socket_fd == -1) { perror("socket()"); exit(EXIT_FAILURE); } ret = bind(socket_fd, (const struct sockaddr *)(&sanl), sizeof(sanl)); if (ret == -1) { perror("bind()"); exit(EXIT_FAILURE); } else { printf("%s: bound to group %d\n", argv[0], sanl.nl_groups); } FD_ZERO(&rfds); FD_SET(socket_fd, &rfds); while (1) { ret = select(socket_fd+1, &rfds, NULL, NULL, NULL); if (ret == -1) { perror("select()"); exit(EXIT_FAILURE); } else if (ret == 0) { printf("%s: Unexpected select() timeout.\n", argv[0]); break; } memset(nlh, 0, sizeof(nlh)); ret = recvmsg(socket_fd, &msg, MSG_DONTWAIT); if (ret > 0) { printf("%s: received(%d): %*s\n", argv[0], ((struct nlmsghdr*)nlh)->nlmsg_len - NLMSG_HDRLEN, ((struct nlmsghdr*)nlh)->nlmsg_len - NLMSG_HDRLEN, (char*)(NLMSG_DATA((struct nlmsghdr*)(nlh)))); } else if (ret == 0) { printf("%s: kaudit shut down. Exiting.\n", argv[0]); exit(EXIT_SUCCESS); } else { switch (errno) { case EAGAIN: case EINTR: printf("%s: interrupt received\n", argv[0]); break; default: perror("recvmsg()"); exit(EXIT_FAILURE); } } } exit(EXIT_SUCCESS); }