aboutsummaryrefslogtreecommitdiffstats
path: root/key2root-lskeys.c
diff options
context:
space:
mode:
Diffstat (limited to 'key2root-lskeys.c')
-rw-r--r--key2root-lskeys.c143
1 files changed, 142 insertions, 1 deletions
diff --git a/key2root-lskeys.c b/key2root-lskeys.c
index ee1732c..7dee003 100644
--- a/key2root-lskeys.c
+++ b/key2root-lskeys.c
@@ -1,6 +1,11 @@
/* See LICENSE file for copyright and license details. */
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
#include "arg.h"
@@ -16,13 +21,149 @@ usage(void)
}
+static int
+outputkey(char *data, size_t whead, size_t *rheadp, size_t *rhead2p, size_t *linenop, const char *user)
+{
+ int failed = 0;
+ size_t len;
+
+ while (*rhead2p < whead || data[*rhead2p] != '\n')
+ ++*rhead2p;
+
+ if (data[*rhead2p] != '\n')
+ return 0;
+
+ len = *rhead2p - *rheadp;
+ *linenop += 1;
+
+ if (memchr(&data[*rheadp], '\0', len)) {
+ fprintf(stderr, "%s: NUL byte found in /etc/key2root/%s on line %zu\n", argv0, user, *linenop);
+ failed = 1;
+ }
+ if (!memchr(&data[*rheadp], ' ', len)) {
+ fprintf(stderr, "%s: no SP byte found in /etc/key2root/%s on line %zu\n", argv0, user, *linenop);
+ failed = 1;
+ }
+
+ if (!failed) {
+ data[*rhead2p] = '\0';
+ printf("%s %s\n", user, &data[*rheadp]);
+ }
+
+ *rheadp = ++*rhead2p;
+ return failed;
+}
+
+
+static int
+listkeys(int dir, const char *user)
+{
+ int fd, failed = 0;
+ char *data = NULL, *new;
+ size_t size = 0;
+ size_t whead = 0;
+ size_t rhead = 0;
+ size_t rhead2 = 0;
+ size_t lineno = 0;
+ ssize_t r = 1;
+
+ fd = openat(dir, user, O_RDONLY);
+ if (fd < 0) {
+ if (errno == ENOENT)
+ return 0;
+ fprintf(stderr, "%s: openat /etc/key2root/ %s O_RDONLY: %s\n", argv0, user, strerror(errno));
+ return 1;
+ }
+
+ while (r) {
+ if (whead == size) {
+ memmove(data, &data[rhead], whead -= rhead);
+ rhead2 -= rhead;
+ rhead = 0;
+ if (whead == size) {
+ new = realloc(data, size += 1024);
+ if (!new) {
+ fprintf(stderr, "%s: realloc: %s\n", argv0, strerror(errno));
+ close(fd);
+ return 1;
+ }
+ data = new;
+ }
+ }
+ r = read(fd, &data[whead], size - whead);
+ if (r <= 0) {
+ fprintf(stderr, "%s: read /etc/key2root/%s: %s\n", argv0, user, strerror(errno));
+ close(fd);
+ return 1;
+ }
+ whead += (size_t)r;
+
+ while (rhead2 < whead)
+ failed |= outputkey(data, whead, &rhead, &rhead2, &lineno, user);
+ }
+
+ if (rhead != whead)
+ fprintf(stderr, "%s: file truncated: /etc/key2root/%s\n", argv0, user);
+
+ close(fd);
+ return failed;
+}
+
+
int
main(int argc, char *argv[])
{
+ int failed = 0, fd;
+ DIR *dir;
+ struct dirent *f;
+
ARGBEGIN {
default:
usage();
} ARGEND;
- return 0;
+ if (argc) {
+ fd = open("/etc/key2root/", O_PATH);
+ if (fd < 0) {
+ if (errno == ENOENT)
+ return 0;
+ fprintf(stderr, "%s: open /etc/key2root/ O_PATH: %s\n", argv0, strerror(errno));
+ exit(1);
+ }
+ for (; *argv; argv++) {
+ if (!(*argv)[0] || (*argv)[0] == '.' || strchr(*argv, '/') || strchr(*argv, '~')) {
+ fprintf(stderr, "%s: bad user name specified: %s\n", argv0, *argv);
+ failed = 1;
+ } else {
+ failed |= listkeys(fd, *argv);
+ }
+ }
+ close(fd);
+ } else {
+ dir = opendir("/etc/key2root/");
+ if (!dir) {
+ if (errno == ENOENT)
+ return 0;
+ fprintf(stderr, "%s: opendir /etc/key2root/: %s\n", argv0, strerror(errno));
+ exit(1);
+ }
+ fd = dirfd(dir);
+ if (fd < 0)
+ abort();
+ while ((errno = 0, f = readdir(dir))) {
+ if (f->d_name[0] == '.' || strchr(f->d_name, '~'))
+ continue;
+ listkeys(fd, f->d_name);
+ }
+ if (errno || closedir(dir)) {
+ fprintf(stderr, "%s: readdir /etc/key2root/: %s\n", argv0, strerror(errno));
+ exit(1);
+ }
+ }
+
+ if (fflush(stdout) || ferror(stdout) || fclose(stdout)) {
+ fprintf(stderr, "%s: print: %s\n", argv0, strerror(errno));
+ exit(1);
+ }
+ return failed;
}