// Mateusz Guzik, https://bugzilla.redhat.com/show_bug.cgi?id=1097315#c19 #include #include #include #include #include #include #include #include #include #include static int nl_open (void) { return socket (AF_NETLINK, SOCK_RAW, NETLINK_AUDIT); } static int nl_send (int fd, unsigned type, unsigned flags, const void *data, size_t size) { struct sockaddr_nl addr; struct msghdr msg; struct nlmsghdr nlm; struct iovec iov[2]; ssize_t res; nlm.nlmsg_len = NLMSG_LENGTH (size); nlm.nlmsg_type = type; nlm.nlmsg_flags = NLM_F_REQUEST | flags; nlm.nlmsg_seq = 0; nlm.nlmsg_pid = 0; iov[0].iov_base = &nlm; iov[0].iov_len = sizeof (nlm); iov[1].iov_base = (void *)data; iov[1].iov_len = size; addr.nl_family = AF_NETLINK; addr.nl_pid = 0; addr.nl_groups = 0; msg.msg_name = &addr; msg.msg_namelen = sizeof (addr); msg.msg_iov = iov; msg.msg_iovlen = 2; msg.msg_control = NULL; msg.msg_controllen = 0; msg.msg_flags = 0; res = sendmsg (fd, &msg, 0); if (res == -1) return -1; if ((size_t)res != nlm.nlmsg_len) { errno = EIO; return -1; } return 0; } static int nl_recv (int fd, unsigned type, void *buf, size_t size) { struct sockaddr_nl addr; struct msghdr msg; struct nlmsghdr nlm; struct iovec iov[2]; ssize_t res; again: iov[0].iov_base = &nlm; iov[0].iov_len = sizeof (nlm); msg.msg_name = &addr; msg.msg_namelen = sizeof (addr); msg.msg_iov = iov; msg.msg_iovlen = 1; msg.msg_control = NULL; msg.msg_controllen = 0; if (type != NLMSG_ERROR) { res = recvmsg (fd, &msg, MSG_PEEK); if (res == -1) return -1; if (res != NLMSG_LENGTH (0)) { errno = EIO; return -1; } if (nlm.nlmsg_type == NLMSG_ERROR) { struct nlmsgerr err; iov[1].iov_base = &err; iov[1].iov_len = sizeof (err); msg.msg_iovlen = 2; res = recvmsg (fd, &msg, 0); if (res == -1) return -1; if ((size_t)res != NLMSG_LENGTH (sizeof (err)) || nlm.nlmsg_type != NLMSG_ERROR) { errno = EIO; return -1; } if (err.error == 0) goto again; errno = -err.error; return -1; } } if (size != 0) { iov[1].iov_base = buf; iov[1].iov_len = size; msg.msg_iovlen = 2; } res = recvmsg (fd, &msg, 0); if (res == -1) return -1; if ((size_t)res != NLMSG_LENGTH (size) || nlm.nlmsg_type != type) { errno = EIO; return -1; } return 0; } static int nl_recv_ack (int fd) { struct nlmsgerr err; if (nl_recv (fd, NLMSG_ERROR, &err, sizeof (err)) != 0) return -1; if (err.error != 0) { errno = -err.error; return -1; } return 0; } int main(void) { struct audit_tty_status *old_status, new_status = { 0 }; int fd; int i=0; int h = 0; fd = nl_open(); if (fd < 0) { perror("nl_open"); exit(1); } new_status.enabled = 1; if (nl_send (fd, AUDIT_TTY_SET, NLM_F_ACK, &new_status, sizeof (new_status)) != 0 || nl_recv_ack (fd) != 0) { fprintf(stderr, "failed\n"); exit(1); } printf("foo bar\n"); //getchar(); for (;;) { audit_log_user_message(fd, AUDIT_USER_TTY, "foo", "bar", "baz", "quux", 1); i = (i+1) & 65535; (i == 0 ) && printf("heartbeat %d\n", h+=1); } close(fd); }