aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--key2root-addkey.c2
-rw-r--r--key2root.82
-rw-r--r--key2root.c155
3 files changed, 153 insertions, 6 deletions
diff --git a/key2root-addkey.c b/key2root-addkey.c
index 5b3f1ee..78435f3 100644
--- a/key2root-addkey.c
+++ b/key2root-addkey.c
@@ -231,7 +231,7 @@ main(int argc, char *argv[])
}
for (i = 0; i < key_len; i++)
if (!key[i])
- key[i] = 255;
+ key[i] = (char)255;
key[key_len] = '\0';
hash = crypt(key, parameters);
if (!hash)
diff --git a/key2root.8 b/key2root.8
index 9cb2652..3747254 100644
--- a/key2root.8
+++ b/key2root.8
@@ -97,7 +97,7 @@ If the
utility fails it will exit with one of the following statuses:
.TP
124
-Authentication failed.
+Authentication failed. (May have an actual error as the cause.)
.TP
125
A error occurred.
diff --git a/key2root.c b/key2root.c
index 3ad97de..77ed0ac 100644
--- a/key2root.c
+++ b/key2root.c
@@ -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) {