/* See LICENSE file for copyright and license details. */ #include #include #include #include #include #include #include #include "arg.h" char *argv0; static void usage(void) { fprintf(stderr, "usage: %s [user] ...\n", argv0); exit(1); } 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 %s/%s on line %zu\n", argv0, KEYPATH, user, *linenop); failed = 1; } if (!memchr(&data[*rheadp], ' ', len)) { fprintf(stderr, "%s: no SP byte found in %s/%s on line %zu\n", argv0, KEYPATH, 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 %s/ %s O_RDONLY: %s\n", argv0, KEYPATH, 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 %s/%s: %s\n", argv0, KEYPATH, 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) { failed = 1; fprintf(stderr, "%s: file truncated: %s/%s\n", argv0, KEYPATH, user); if (memchr(&data[rhead], '\0', whead - rhead)) fprintf(stderr, "%s: NUL byte found in %s/%s on line %zu\n", argv0, KEYPATH, user, lineno + 1); } close(fd); return failed; } int main(int argc, char *argv[]) { int failed = 0, fd; DIR *dir; struct dirent *f; ARGBEGIN { default: usage(); } ARGEND; if (argc) { fd = open(KEYPATH"/", O_PATH); if (fd < 0) { if (errno == ENOENT) return 0; fprintf(stderr, "%s: open %s/ O_PATH: %s\n", argv0, KEYPATH, 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(KEYPATH"/"); if (!dir) { if (errno == ENOENT) return 0; fprintf(stderr, "%s: opendir %s/: %s\n", argv0, KEYPATH, 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 %s/: %s\n", argv0, KEYPATH, strerror(errno)); exit(1); } } if (fflush(stdout) || ferror(stdout) || fclose(stdout)) { fprintf(stderr, "%s: print: %s\n", argv0, strerror(errno)); exit(1); } return failed; }