diff options
Diffstat (limited to 'ssh')
| -rw-r--r-- | ssh/client.c | 50 | ||||
| -rw-r--r-- | ssh/ssh_client.c | 6 | ||||
| -rw-r--r-- | ssh/sshnc.h | 2 | ||||
| -rw-r--r-- | ssh/tomsg_clientlib.c | 17 | ||||
| -rw-r--r-- | ssh/tomsg_clientlib.h | 12 | 
5 files changed, 71 insertions, 16 deletions
| diff --git a/ssh/client.c b/ssh/client.c index 64f8f57..80e14a4 100644 --- a/ssh/client.c +++ b/ssh/client.c @@ -83,6 +83,38 @@ static void splice_scanned(struct readbuffer *rb) {  	rb->newline_cursor = 0;  } +static bool prompt_yn(struct readbuffer *rb, const char *text) { +	printf("%s [y/n] ", text); +	fflush(stdout); + +	while (true) { +		struct string_view line = extract_line(rb); +		if (line.s == NULL) { +			read_more_data(STDIN_FILENO, rb); +			continue; +		} + +		splice_scanned(rb); + +		if (line.len <= 3) { +			char buf[4]; +			memcpy(buf, line.s, line.len); +			buf[line.len] = '\0'; + +			if (strcmp(buf, "y") == 0 || strcmp(buf, "yes") == 0) { +				return true; +			} + +			if (strcmp(buf, "n") == 0 || strcmp(buf, "no") == 0) { +				return false; +			} +		} + +		printf("Please answer with 'y', 'n', 'yes' or 'no'. [y/n] "); +		fflush(stdout); +	} +} +  static struct string_view tokenise_greedy(struct string_view *line) {  	sv_skip_whitespace(line);  	return sv_tokenise_word(line); @@ -415,6 +447,17 @@ static void handle_event(struct state *state, const struct tomsg_event event) {  	}  } +static bool hostkey_checker(const unsigned char *hash, size_t length, void *stdinbuf_) { +	struct readbuffer *stdinbuf = stdinbuf_; + +	const char *fingerprint = tomsg_print_hash(hash, length); + +	printf("Server host key fingerprint: %s\n", fingerprint); +	return prompt_yn(stdinbuf, +		"Does this hash match the one given to you by the server administrator, or by a\n" +		"member that you trust and is already connected to the server?"); +} +  int main(int argc, char **argv) {  	if (argc != 2) {  		printf("Usage: %s <hostname:port>\n", argv[0]); @@ -428,10 +471,13 @@ int main(int argc, char **argv) {  		return 1;  	} +	struct readbuffer stdinbuf = readbuffer_new(); +  	printf("Connecting...\n");  	struct tomsg_client *client; -	enum tomsg_retval ret = tomsg_connect(hostname, port, &client); +	enum tomsg_retval ret = tomsg_connect( +			hostname, port, hostkey_checker, &stdinbuf, &client);  	if (ret != TOMSG_OK) {  		printf("Could not connect: %s\n", tomsg_strerror(ret));  		return 1; @@ -439,8 +485,6 @@ int main(int argc, char **argv) {  	printf("Connected.\n"); -	struct readbuffer stdinbuf = readbuffer_new(); -  	struct state state = (struct state){  		.rooms = NULL,  		.num_rooms = 0, diff --git a/ssh/ssh_client.c b/ssh/ssh_client.c index 3e4a7c6..f09aaac 100644 --- a/ssh/ssh_client.c +++ b/ssh/ssh_client.c @@ -10,7 +10,7 @@  static bool prompt_yn(const char *text) { -	printf("%s", text); +	printf("%s [y/n] ", text);  	fflush(stdout);  	bool response; @@ -37,7 +37,7 @@ static bool prompt_yn(const char *text) {  			break;  		} -		printf("Please answer with 'y', 'n', 'yes' or 'no'. [y/n]"); +		printf("Please answer with 'y', 'n', 'yes' or 'no'. [y/n] ");  		fflush(stdout);  	} @@ -51,7 +51,7 @@ static bool hostkey_checker(const unsigned char *hash, size_t length, void *user  	bool response = prompt_yn(  			"Does this hash match the one given to you by the server administrator, or by a\n" -			"member that you trust and is already connected to the server? [y/n] "); +			"member that you trust and is already connected to the server?");  	if (!response) {  		printf("Disconnecting.\n");  	} diff --git a/ssh/sshnc.h b/ssh/sshnc.h index 1e82075..5ee742a 100644 --- a/ssh/sshnc.h +++ b/ssh/sshnc.h @@ -64,7 +64,7 @@ enum sshnc_retval sshnc_connect(  	const char *username,  	const char *subsystem,  	sshnc_hostkey_checker_t checker, -	void *userdata, +	void *userdata,  // for checker  	struct sshnc_client **client  // output  ); diff --git a/ssh/tomsg_clientlib.c b/ssh/tomsg_clientlib.c index 9898b66..80a9bf3 100644 --- a/ssh/tomsg_clientlib.c +++ b/ssh/tomsg_clientlib.c @@ -34,13 +34,6 @@ struct tomsg_client {  static size_t min_size_t(size_t a, size_t b) { return a < b ? a : b; } -static bool hostkey_checker(const unsigned char *hash, size_t length, void *userdata) { -	(void)userdata; -	static const char *preload = "SHA256:ppz/McaESpOQy0O3kbaIi1LPZ37/YtrdC+y9102Y0+I"; -	const char *fingerprint = sshnc_print_hash(hash, length); -	return strcmp(fingerprint, preload) == 0; -} -  static bool hasspacelf(const char *string) {  	for (size_t i = 0; string[i]; i++)  		if (string[i] == ' ' || string[i] == '\n') return true; @@ -139,6 +132,10 @@ static void splice_scanned_buffer_part(struct tomsg_client *client) {  	client->buffer_newline_cursor = 0;  } +const char* tomsg_print_hash(const unsigned char *hash, size_t length) { +	return sshnc_print_hash(hash, length); +} +  const char* tomsg_strerror(enum tomsg_retval code) {  	switch (code) {  		case TOMSG_OK: return "Success"; @@ -190,13 +187,15 @@ static enum tomsg_retval version_negotiation(struct tomsg_client *client) {  }  enum tomsg_retval tomsg_connect( -		const char *hostname, int port, struct tomsg_client **clientp) { +		const char *hostname, int port, +		tomsg_hostkey_checker_t checker, void *userdata, +		struct tomsg_client **clientp) {  	// In case we throw an error along the way  	*clientp = NULL;  	struct sshnc_client *conn;  	enum sshnc_retval ret = sshnc_connect( -			hostname, port, "tomsg", "tomsg", hostkey_checker, NULL, &conn); +			hostname, port, "tomsg", "tomsg", checker, userdata, &conn);  	if (ret == SSHNC_ERR_CONNECT) return TOMSG_ERR_CONNECT;  	if (ret != SSHNC_OK) return TOMSG_ERR_TRANSPORT; diff --git a/ssh/tomsg_clientlib.h b/ssh/tomsg_clientlib.h index 58ad4d4..03f1fcf 100644 --- a/ssh/tomsg_clientlib.h +++ b/ssh/tomsg_clientlib.h @@ -30,6 +30,16 @@ enum tomsg_retval {  	TOMSG_ERR_MEMORY,     // Error allocating memory  }; +// Should return 'true' if the key is trusted, 'false' otherwise. The hash is +// sha256 in byte form, not yet encoded in hexadecimal or similar. The +// 'userdata' pointer comes from the 'tomsg_connect' invocation. +typedef bool (*tomsg_hostkey_checker_t)( +	const unsigned char *hash, size_t length, void *userdata); + +// Convenience function to convert a hash to a human-readable form. Returns a +// reference to an internal static buffer. +const char* tomsg_print_hash(const unsigned char *hash, size_t length); +  // Returns reference to internal static buffer.  const char* tomsg_strerror(enum tomsg_retval code); @@ -37,6 +47,8 @@ const char* tomsg_strerror(enum tomsg_retval code);  // TOMSG_OK. On error, stores NULL in 'client' and returns an error code.  enum tomsg_retval tomsg_connect(  	const char *hostname, int port, +	tomsg_hostkey_checker_t checker, +	void *userdata,  // for checker  	struct tomsg_client **client  // output  ); | 
