diff options
Diffstat (limited to '')
| -rw-r--r-- | key2root-addkey.c | 13 | ||||
| -rw-r--r-- | key2root-lskeys.c | 6 | ||||
| -rw-r--r-- | key2root-rmkey.8 | 5 | ||||
| -rw-r--r-- | key2root-rmkey.c | 188 | 
4 files changed, 205 insertions, 7 deletions
| diff --git a/key2root-addkey.c b/key2root-addkey.c index d5ec701..c80ebbe 100644 --- a/key2root-addkey.c +++ b/key2root-addkey.c @@ -1,6 +1,10 @@  /* See LICENSE file for copyright and license details. */ +#include <sys/mman.h> +#include <errno.h> +#include <fcntl.h>  #include <stdio.h>  #include <stdlib.h> +#include <string.h>  #include <unistd.h>  #include "arg.h" @@ -56,7 +60,14 @@ main(int argc, char *argv[])  	if (failed)  		return 1; -	/* TODO */ +	if (mlockall(MCL_CURRENT | MCL_FUTURE)) { +		fprintf(stderr, "%s: mlockall MCL_CURRENT|MCL_FUTURE: %s\n", argv0, strerror(errno)); +		exit(1); +	} + +	/* TODO hash input */ +	/* TODO add or replace key */ +	/* TODO save changes, mode shall be 0700 */  	return 0;  } diff --git a/key2root-lskeys.c b/key2root-lskeys.c index 7dee003..69e6319 100644 --- a/key2root-lskeys.c +++ b/key2root-lskeys.c @@ -91,7 +91,7 @@ listkeys(int dir, const char *user)  			}  		}  		r = read(fd, &data[whead], size - whead); -		if (r <= 0) { +		if (r < 0) {  			fprintf(stderr, "%s: read /etc/key2root/%s: %s\n", argv0, user, strerror(errno));  			close(fd);  			return 1; @@ -102,8 +102,10 @@ listkeys(int dir, const char *user)  			failed |= outputkey(data, whead, &rhead, &rhead2, &lineno, user);  	} -	if (rhead != whead) +	if (rhead != whead) {  		fprintf(stderr, "%s: file truncated: /etc/key2root/%s\n", argv0, user); +		failed = 1; +	}  	close(fd);  	return failed; diff --git a/key2root-rmkey.8 b/key2root-rmkey.8 index fe01c93..d79544c 100644 --- a/key2root-rmkey.8 +++ b/key2root-rmkey.8 @@ -97,6 +97,11 @@ associated with the user name, and the user name must be specified  when removing it. Likewise if a keyfile was added with a user ID  specified, it is only associated with the user ID, and the user ID  must be specified when removing it. +.PP +To completely remove a user, remove +.BI /etc/key2root/ user-id +and +.BR /etc/key2root/ \fIuser-name\fP.  .SH BUGS  None. diff --git a/key2root-rmkey.c b/key2root-rmkey.c index f2ab34d..d3dbc16 100644 --- a/key2root-rmkey.c +++ b/key2root-rmkey.c @@ -1,6 +1,10 @@  /* See LICENSE file for copyright and license details. */ +#include <errno.h> +#include <fcntl.h>  #include <stdio.h>  #include <stdlib.h> +#include <string.h> +#include <unistd.h>  #include "arg.h" @@ -16,11 +20,118 @@ usage(void)  } +static int +writeall(int fd, const char *data, size_t len) +{ +	size_t off = 0; +	ssize_t r; + +	for (;;) { +		r = write(fd, &data[off], len - off); +		if (r < 0) +			return -1; +		off += (size_t)r; +	} + +	return 0; +} + + +static void +removekeys(char *data, size_t *wheadp, size_t *rheadp, size_t *rhead2p, size_t *linenop, +           const char *path, const char **keys, size_t *nkeysp) +{ +	int failed = 0; +	size_t len, klen; +	size_t i; + +	while (*rhead2p < *wheadp || data[*rhead2p] != '\n') +		++*rhead2p; + +	if (data[*rhead2p] != '\n') +		return; + +	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; +	} +	if (!memchr(&data[*rheadp], ' ', len)) { +		fprintf(stderr, "%s: no SP byte found in %s on line %zu\n", argv0, path, *linenop); +		failed = 1; +	} + +	if (failed) { +		goto no_match; +	} else { +		for (i = 0; i < *nkeysp; i++) { +			klen = strlen(keys[i]); +			if (klen >= len || data[*rheadp + klen] != ' ' || memcpy(&data[*rheadp], keys[i], klen)) +				continue; +			memmove(&keys[i], &keys[i + 1], (--*nkeysp - i) * sizeof(*keys)); +			goto match; +		} +	no_match: +		*rheadp = ++*rhead2p; +		return; +	match: +		++*rhead2p; +		memmove(&data[*rheadp], &data[*rhead2p], *wheadp - *rhead2p); +		*wheadp -= *rhead2p - *rheadp; +		*rhead2p = *rheadp; +	} +} + + +static void +loadandremove(int fd, char **datap, size_t *lenp, size_t *sizep, const char **keys, size_t *nkeysp, const char *path) +{ +	char *new; +	size_t lineno = 0; +	ssize_t r = 1; +	size_t rhead = 0; +	size_t rhead2 = 0; + +	while (r) { +		if (*lenp == *sizep) { +			new = realloc(*datap, *sizep += 4096); +			if (!new) { +				fprintf(stderr, "%s: realloc: %s\n", argv0, strerror(errno)); +				exit(1); +			} +			*datap = new; +		} + +		r = read(fd, &(*datap)[*lenp], *sizep - *lenp); +		if (r < 0) { +			fprintf(stderr, "%s: read %s: %s\n", argv0, path, strerror(errno)); +			exit(1); +		} +		*lenp += (size_t)r; + +		while (rhead2 < *lenp) +			removekeys(*datap, lenp, &rhead, &rhead2, &lineno, path, keys, nkeysp); +	} + +	if (rhead != *lenp) +		fprintf(stderr, "%s: file truncated: %s\n", argv0, path); +} + +  int  main(int argc, char *argv[])  { +	char *path, *path2;  	const char *user; -	int i, failed = 0; +	int failed = 0; +	const char **keys; +	size_t i, nkeys; +	int fd; +	char *data = NULL; +	size_t data_len = 0; +	size_t data_size = 0;  	ARGBEGIN {  	default: @@ -37,7 +148,7 @@ main(int argc, char *argv[])  		fprintf(stderr, "%s: bad user name specified: %s\n", argv0, user);  		failed = 1;  	} -	for (i = 0; i < argc; i++) { +	for (i = 0; i < (size_t)argc; i++) {  		if (argv[i][strcspn(argv[i], " \t\f\n\r\v")]) {  			fprintf(stderr, "%s: bad key name specified: %s, includes whitespace\n", argv0, argv[i]);  			failed = 1; @@ -46,7 +157,76 @@ main(int argc, char *argv[])  	if (failed)  		return 1; -	/* TODO */ +	nkeys = (size_t)argc; +	keys = calloc(nkeys, sizeof(*keys)); +	if (!keys) { +		fprintf(stderr, "%s: calloc: %s\n", argv0, strerror(errno)); +		exit(1); +	} +	for (i = 0; i < (size_t)argc; i++) +		keys[i] = argv[i]; -	return 0; +	path = malloc(sizeof("/etc/key2root/") + strlen(user)); +	if (!path) { +		fprintf(stderr, "%s: malloc: %s\n", argv0, strerror(errno)); +		exit(1); +	} +	path2 = malloc(sizeof("/etc/key2root/~") + strlen(user)); +	if (!path) { +		fprintf(stderr, "%s: malloc: %s\n", argv0, strerror(errno)); +		exit(1); +	} +	stpcpy(stpcpy(path, "/etc/key2root/"), user); +	stpcpy(stpcpy(path2, path), "~"); + +	fd = open(path, O_RDONLY); +	if (fd < 0) { +		if (errno == ENOENT) +			goto out; +		fprintf(stderr, "%s: open %s O_RDONLY: %s\n", argv0, path, strerror(errno)); +		exit(1); +	} +	loadandremove(fd, &data, &data_len, &data_size, keys, &nkeys, path); +	if (close(fd)) { +		fprintf(stderr, "%s: read %s: %s\n", argv0, path, strerror(errno)); +		exit(1); +	} + +out: +	for (i = 0; i < nkeys; i++) +		fprintf(stderr, "%s: key not found for %s: %s\n", argv0, user, keys[i]); +	failed |= !nkeys; + +	if (nkeys != (size_t)argc) { +		if (!data_len) { +			if (unlink(path)) { +				fprintf(stderr, "%s: unlink %s: %s\n", argv0, path, strerror(errno)); +				failed = 1; +			} +		} else { +			fd = open(path2, O_WRONLY | O_CREAT | O_EXCL, 0600); +			if (fd < 0) { +				fprintf(stderr, "%s: open %s O_WRONLY|O_CREAT|O_EXCL 0600: %s\n", argv0, path2, strerror(errno)); +				exit(1); +			} +			if (writeall(fd, data, data_len) || close(fd)) { +				fprintf(stderr, "%s: write %s: %s\n", argv0, path2, strerror(errno)); +				if (unlink(path2)) +					fprintf(stderr, "%s: unlink %s: %s\n", argv0, path2, strerror(errno)); +				exit(1); +			} +			if (rename(path2, path)) { +				fprintf(stderr, "%s: rename %s %s: %s\n", argv0, path2, path, strerror(errno)); +				if (unlink(path2)) +					fprintf(stderr, "%s: unlink %s: %s\n", argv0, path2, strerror(errno)); +				exit(1); +			} +		} +	} + +	free(keys); +	free(path); +	free(path2); +	free(data); +	return failed;  } | 
