diff options
Diffstat (limited to '')
| -rw-r--r-- | key2root-addkey.c | 2 | ||||
| -rw-r--r-- | key2root.8 | 2 | ||||
| -rw-r--r-- | key2root.c | 153 | 
3 files changed, 152 insertions, 5 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) @@ -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. @@ -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;  	} +	for (i = 0; i < key_len; i++) +		if (!key[i]) +			key[i] = (char)255; +	key[key_len] = '\0'; -	/* TODO authenticate */ +	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) { | 
