diff options
Diffstat (limited to 'key2root.c')
-rw-r--r-- | key2root.c | 155 |
1 files changed, 151 insertions, 4 deletions
@@ -3,7 +3,9 @@ #include <sys/socket.h> #include <sys/syscall.h> #include <errno.h> +#include <fcntl.h> #include <pwd.h> +#include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -120,6 +122,8 @@ forward(char *data, size_t len) close(fds[1]); return -1; case 0: + if (mlockall(MCL_CURRENT)) + fprintf(stderr, "%s: mlockall MCL_CURRENT: %s\n", argv0, strerror(errno)); close(fds[0]); break; default: @@ -219,6 +223,115 @@ set_environ(void) } +static int +checkauth(char *data, size_t whead, size_t *rheadp, size_t *rhead2p, size_t *linenop, const char *path, + const char *keyname, size_t keyname_len, const char *key, size_t key_len, int *key_foundp) +{ + int failed = 0, match; + char *hash, *sp; + 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 on line %zu\n", argv0, path, *linenop); + failed = 1; + } + sp = memchr(&data[*rheadp], ' ', len); + if (!sp) { + fprintf(stderr, "%s: no SP byte found in %s on line %zu\n", argv0, path, *linenop); + failed = 1; + } + + if (!failed && !keyname) { + keyname_len = (size_t)(sp - &data[*rheadp]); + goto check; + } else if (failed || keyname_len >= len || data[*rheadp + keyname_len] != ' ' || + memcpy(&data[*rheadp], keyname, keyname_len)) { + *rheadp = ++*rhead2p; + return 0; + } else { + check: + *rheadp += keyname_len + 1; + *key_foundp = 1; + data[(*rhead2p)++] = '\0'; + hash = crypt(key, &data[*rheadp]); + match = hash && strlen(hash) == key_len && !memcmp(hash, key, key_len); + *rheadp = *rhead2p; + return match; + } +} + + +static int +authenticate(const char *path, const char *keyname, const char *key, size_t key_len, int *key_foundp) +{ + int fd; + char *data = NULL; + size_t size = 0; + size_t whead = 0; + size_t rhead = 0; + size_t rhead2 = 0; + size_t lineno = 0; + ssize_t r = 1; + size_t keyname_len = keyname ? strlen(keyname) : 0; + + fd = open(path, O_RDONLY); + if (fd < 0) { + if (errno != ENOENT) + fprintf(stderr, "%s: open %s O_RDONLY: %s\n", argv0, path, strerror(errno)); + return 0; + } + + while (r) { + if (whead == size) { + memmove(data, &data[rhead], whead -= rhead); + rhead2 -= rhead; + rhead = 0; + if (whead == size) { + data = realloc(data, size += 1024); + if (!data) { + fprintf(stderr, "%s: realloc: %s\n", argv0, strerror(errno)); + close(fd); + return 0; + } + } + } + r = read(fd, &data[whead], size - whead); + if (r < 0) { + fprintf(stderr, "%s: read %s: %s\n", argv0, path, strerror(errno)); + close(fd); + return 0; + } + whead += (size_t)r; + + while (rhead2 < whead) { + if (checkauth(data, whead, &rhead, &rhead2, &lineno, path, + keyname, keyname_len, key, key_len, key_foundp)) { + close(fd); + return 1; + } + } + } + + if (rhead != whead) { + fprintf(stderr, "%s: file truncated: %s\n", argv0, path); + if (memchr(&data[rhead], '\0', whead - rhead)) + fprintf(stderr, "%s: NUL byte found in %s on line %zu\n", argv0, path, lineno + 1); + } + + close(fd); + return 0; +} + + int main(int argc, char *argv[]) { @@ -229,7 +342,11 @@ main(int argc, char *argv[]) size_t key_len = 0; size_t key_size = 0; ssize_t r; - int fd; + int fd, key_found; + char path_user_id[sizeof(KEYPATH"/") + 3 * sizeof(uintmax_t)]; + char *path_user_name; + struct passwd *pwd; + size_t i; ARGBEGIN { case 'e': @@ -252,9 +369,26 @@ main(int argc, char *argv[]) exit(EXIT_ERROR); } + sprintf(path_user_id, "%s/%ju", KEYPATH, (uintmax_t)getuid()); + errno = 0; + pwd = getpwuid(getuid()); + if (!pwd || !pwd->pw_name || !*pwd->pw_name) { + if (errno) + fprintf(stderr, "%s: getpwuid: %s\n", argv0, strerror(errno)); + else + fprintf(stderr, "%s: your user does not exist\n", argv0); + exit(EXIT_ERROR); + } + path_user_name = malloc(sizeof(KEYPATH"/") + strlen(pwd->pw_name)); + if (!path_user_name) { + fprintf(stderr, "%s: malloc: %s\n", argv0, strerror(errno)); + exit(EXIT_ERROR); + } + stpcpy(stpcpy(path_user_name, KEYPATH"/"), pwd->pw_name); + for (;;) { if (key_len == key_size) { - key_new = malloc(key_size += 1024); + key_new = malloc(1 + (key_size += 1024)); if (!key_new) { explicit_bzero(key, key_len); fprintf(stderr, "%s: malloc: %s\n", argv0, strerror(errno)); @@ -275,8 +409,21 @@ main(int argc, char *argv[]) } key_len += (size_t)r; } - - /* TODO authenticate */ + for (i = 0; i < key_len; i++) + if (!key[i]) + key[i] = (char)255; + key[key_len] = '\0'; + + key_found = 0; + if (!authenticate(path_user_id, key_name, key, key_len, &key_found) && + !authenticate(path_user_name, key_name, key, key_len, &key_found)) { + fprintf(stderr, "%s: authentication failed: %s\n", argv0, + key_name ? (key_found ? "key mismatch" : "key not found") + : (key_found ? "no match key found" : "no key found")); + explicit_bzero(key, key_len); + exit(EXIT_AUTH); + } + free(path_user_name); fd = forward(key, key_len); if (fd < 0) { |