123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186 |
- // SPDX-License-Identifier: GPL-2.0
- /* Use watch_queue API to watch for notifications.
- *
- * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved.
- * Written by David Howells ([email protected])
- */
- #define _GNU_SOURCE
- #include <stdbool.h>
- #include <stdarg.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <signal.h>
- #include <unistd.h>
- #include <errno.h>
- #include <sys/ioctl.h>
- #include <limits.h>
- #include <linux/watch_queue.h>
- #include <linux/unistd.h>
- #include <linux/keyctl.h>
- #ifndef KEYCTL_WATCH_KEY
- #define KEYCTL_WATCH_KEY -1
- #endif
- #ifndef __NR_keyctl
- #define __NR_keyctl -1
- #endif
- #define BUF_SIZE 256
- static long keyctl_watch_key(int key, int watch_fd, int watch_id)
- {
- return syscall(__NR_keyctl, KEYCTL_WATCH_KEY, key, watch_fd, watch_id);
- }
- static const char *key_subtypes[256] = {
- [NOTIFY_KEY_INSTANTIATED] = "instantiated",
- [NOTIFY_KEY_UPDATED] = "updated",
- [NOTIFY_KEY_LINKED] = "linked",
- [NOTIFY_KEY_UNLINKED] = "unlinked",
- [NOTIFY_KEY_CLEARED] = "cleared",
- [NOTIFY_KEY_REVOKED] = "revoked",
- [NOTIFY_KEY_INVALIDATED] = "invalidated",
- [NOTIFY_KEY_SETATTR] = "setattr",
- };
- static void saw_key_change(struct watch_notification *n, size_t len)
- {
- struct key_notification *k = (struct key_notification *)n;
- if (len != sizeof(struct key_notification)) {
- fprintf(stderr, "Incorrect key message length\n");
- return;
- }
- printf("KEY %08x change=%u[%s] aux=%u\n",
- k->key_id, n->subtype, key_subtypes[n->subtype], k->aux);
- }
- /*
- * Consume and display events.
- */
- static void consumer(int fd)
- {
- unsigned char buffer[433], *p, *end;
- union {
- struct watch_notification n;
- unsigned char buf1[128];
- } n;
- ssize_t buf_len;
- for (;;) {
- buf_len = read(fd, buffer, sizeof(buffer));
- if (buf_len == -1) {
- perror("read");
- exit(1);
- }
- if (buf_len == 0) {
- printf("-- END --\n");
- return;
- }
- if (buf_len > sizeof(buffer)) {
- fprintf(stderr, "Read buffer overrun: %zd\n", buf_len);
- return;
- }
- printf("read() = %zd\n", buf_len);
- p = buffer;
- end = buffer + buf_len;
- while (p < end) {
- size_t largest, len;
- largest = end - p;
- if (largest > 128)
- largest = 128;
- if (largest < sizeof(struct watch_notification)) {
- fprintf(stderr, "Short message header: %zu\n", largest);
- return;
- }
- memcpy(&n, p, largest);
- printf("NOTIFY[%03zx]: ty=%06x sy=%02x i=%08x\n",
- p - buffer, n.n.type, n.n.subtype, n.n.info);
- len = n.n.info & WATCH_INFO_LENGTH;
- if (len < sizeof(n.n) || len > largest) {
- fprintf(stderr, "Bad message length: %zu/%zu\n", len, largest);
- exit(1);
- }
- switch (n.n.type) {
- case WATCH_TYPE_META:
- switch (n.n.subtype) {
- case WATCH_META_REMOVAL_NOTIFICATION:
- printf("REMOVAL of watchpoint %08x\n",
- (n.n.info & WATCH_INFO_ID) >>
- WATCH_INFO_ID__SHIFT);
- break;
- case WATCH_META_LOSS_NOTIFICATION:
- printf("-- LOSS --\n");
- break;
- default:
- printf("other meta record\n");
- break;
- }
- break;
- case WATCH_TYPE_KEY_NOTIFY:
- saw_key_change(&n.n, len);
- break;
- default:
- printf("other type\n");
- break;
- }
- p += len;
- }
- }
- }
- static struct watch_notification_filter filter = {
- .nr_filters = 1,
- .filters = {
- [0] = {
- .type = WATCH_TYPE_KEY_NOTIFY,
- .subtype_filter[0] = UINT_MAX,
- },
- },
- };
- int main(int argc, char **argv)
- {
- int pipefd[2], fd;
- if (pipe2(pipefd, O_NOTIFICATION_PIPE) == -1) {
- perror("pipe2");
- exit(1);
- }
- fd = pipefd[0];
- if (ioctl(fd, IOC_WATCH_QUEUE_SET_SIZE, BUF_SIZE) == -1) {
- perror("watch_queue(size)");
- exit(1);
- }
- if (ioctl(fd, IOC_WATCH_QUEUE_SET_FILTER, &filter) == -1) {
- perror("watch_queue(filter)");
- exit(1);
- }
- if (keyctl_watch_key(KEY_SPEC_SESSION_KEYRING, fd, 0x01) == -1) {
- perror("keyctl");
- exit(1);
- }
- if (keyctl_watch_key(KEY_SPEC_USER_KEYRING, fd, 0x02) == -1) {
- perror("keyctl");
- exit(1);
- }
- consumer(fd);
- exit(0);
- }
|