Exemplo n.º 1
0
int setup_connection_common(int sock, char* name, CONNECTION_TYPE ctype, int* serverflags) {
	char buf[256];
	u64 tmp64;
	uint64_t mymagic = (name ? opts_magic : cliserv_magic);
	uint32_t tmp32 = 0;

	if(ctype<CONNECTION_TYPE_INIT_PASSWD)
		goto end;
	READ_ALL_ERRCHK(sock, buf, strlen(INIT_PASSWD), err, "Could not read INIT_PASSWD: %s", strerror(errno));
	if(strlen(buf)==0) {
		snprintf(errstr, errstr_len, "Server closed connection");
		goto err;
	}
	if(strncmp(buf, INIT_PASSWD, strlen(INIT_PASSWD))) {
		snprintf(errstr, errstr_len, "INIT_PASSWD does not match");
		goto err;
	}
	if(ctype<CONNECTION_TYPE_CLISERV)
		goto end;
	READ_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err, "Could not read cliserv_magic: %s", strerror(errno));
	tmp64=ntohll(tmp64);
	if(tmp64 != mymagic) {
		strncpy(errstr, "mymagic does not match", errstr_len);
		goto err;
	}
	if(ctype<CONNECTION_TYPE_FULL)
		goto end;
	if(!name) {
		READ_ALL_ERRCHK(sock, &size, sizeof(size), err, "Could not read size: %s", strerror(errno));
		size=ntohll(size);
		READ_ALL_ERRCHK(sock, buf, 128, err, "Could not read data: %s", strerror(errno));
		goto end;
	}
	/* flags */
	READ_ALL_ERRCHK(sock, buf, sizeof(uint16_t), err, "Could not read reserved field: %s", strerror(errno));
	/* reserved field */
	WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err, "Could not write reserved field: %s", strerror(errno));
	/* magic */
	tmp64 = htonll(opts_magic);
	WRITE_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err, "Could not write magic: %s", strerror(errno));
	/* name */
	tmp32 = htonl(NBD_OPT_EXPORT_NAME);
	WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err, "Could not write option: %s", strerror(errno));
	tmp32 = htonl((uint32_t)strlen(name));
	WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err, "Could not write name length: %s", strerror(errno));
	WRITE_ALL_ERRCHK(sock, name, strlen(name), err, "Could not write name:: %s", strerror(errno));
	READ_ALL_ERRCHK(sock, &size, sizeof(size), err, "Could not read size: %s", strerror(errno));
	size = ntohll(size);
	uint16_t flags;
	READ_ALL_ERRCHK(sock, &flags, sizeof(uint16_t), err, "Could not read flags: %s", strerror(errno));
	flags = ntohs(flags);
	*serverflags = flags;
	READ_ALL_ERRCHK(sock, buf, 124, err, "Could not read reserved zeroes: %s", strerror(errno));
	goto end;
err:
	close(sock);
	sock=-1;
end:
	return sock;
}
Exemplo n.º 2
0
int handshake_test(char *name, int sock, char close_sock, int testflags)
{
	int retval = -1;
	int serverflags = 0;
	u64 tmp64;
	uint32_t tmp32 = 0;

	/* This should work */
	if ((sock =
		 setup_connection_common(sock, name,
				  CONNECTION_TYPE_FULL,
				  &serverflags, testflags)) < 0) {
		g_warning("Could not open socket: %s", errstr);
		goto err;
	}

	/* Intentionally throw an unknown option at the server */
	tmp64 = htonll(opts_magic);
	WRITE_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
			 "Could not write magic: %s", strerror(errno));
	tmp32 = htonl(0x7654321);
	WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
			 "Could not write option: %s", strerror(errno));
	tmp32 = htonl((uint32_t) sizeof(tmp32));
	WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
			 "Could not write option length: %s", strerror(errno));
	WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
			 "Could not write option payload: %s", strerror(errno));
	/* Expect proper error from server */
	READ_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
			"Could not read magic: %s", strerror(errno));
	tmp64 = ntohll(tmp64);
	if (tmp64 != 0x3e889045565a9LL) {
		strncpy(errstr, "magic does not match", errstr_len);
		goto err;
	}
	READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
			"Could not read option: %s", strerror(errno));
	tmp32 = ntohl(tmp32);
	if (tmp32 != 0x7654321) {
		strncpy(errstr, "option does not match", errstr_len);
		goto err;
	}
	READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
			"Could not read status: %s", strerror(errno));
	tmp32 = ntohl(tmp32);
	if (tmp32 != NBD_REP_ERR_UNSUP) {
		strncpy(errstr, "status does not match", errstr_len);
		goto err;
	}
	READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
			"Could not read length: %s", strerror(errno));
	tmp32 = ntohl(tmp32);
	while (tmp32) {
		char buf[1024];
		size_t len = tmp32 < sizeof(buf) ? tmp32 : sizeof(buf);
		READ_ALL_ERRCHK(sock, buf, len, err,
				"Could not read payload: %s", strerror(errno));
		tmp32 -= len;
	}


	/* Send NBD_OPT_ABORT to close the connection */
	tmp64 = htonll(opts_magic);
	WRITE_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
			 "Could not write magic: %s", strerror(errno));
	tmp32 = htonl(NBD_OPT_ABORT);
	WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
			 "Could not write option: %s", strerror(errno));
	tmp32 = htonl((uint32_t) 0);
	WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
			 "Could not write option length: %s", strerror(errno));

	retval = 0;

	g_message("Handshake test completed. No errors encountered.");
err:
	return retval;
}
Exemplo n.º 3
0
int setup_connection_common(int sock, char *name, CONNECTION_TYPE ctype,
			    int *serverflags, int testflags)
{
	char buf[256];
	u64 tmp64;
	uint64_t mymagic = (name ? opts_magic : cliserv_magic);
	uint32_t tmp32 = 0;
	uint16_t handshakeflags = 0;
	uint32_t negotiationflags = 0;

	if (ctype < CONNECTION_TYPE_INIT_PASSWD)
		goto end;
	READ_ALL_ERRCHK(sock, buf, strlen(INIT_PASSWD), err,
			"Could not read INIT_PASSWD: %s", strerror(errno));
	if (strlen(buf) == 0) {
		snprintf(errstr, errstr_len, "Server closed connection");
		goto err;
	}
	if (strncmp(buf, INIT_PASSWD, strlen(INIT_PASSWD))) {
		snprintf(errstr, errstr_len, "INIT_PASSWD does not match");
		goto err;
	}
	if (ctype < CONNECTION_TYPE_CLISERV)
		goto end;
	READ_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
			"Could not read cliserv_magic: %s", strerror(errno));
	tmp64 = ntohll(tmp64);
	if (tmp64 != mymagic) {
		strncpy(errstr, "mymagic does not match", errstr_len);
		goto err;
	}
	if (ctype < CONNECTION_TYPE_FULL)
		goto end;
	if (!name) {
		READ_ALL_ERRCHK(sock, &size, sizeof(size), err,
				"Could not read size: %s", strerror(errno));
		size = ntohll(size);
		uint32_t flags;
		READ_ALL_ERRCHK(sock, &flags, sizeof(uint32_t), err,
				"Could not read flags: %s", strerror(errno));
		flags = ntohl(flags);
		*serverflags = flags;
		READ_ALL_ERRCHK(sock, buf, 124, err, "Could not read data: %s",
				strerror(errno));
		goto end;
	}
	/* handshake flags */
	READ_ALL_ERRCHK(sock, &handshakeflags, sizeof(handshakeflags), err,
			"Could not read reserved field: %s", strerror(errno));
	handshakeflags = ntohs(handshakeflags);
	/* negotiation flags */
	if (handshakeflags & NBD_FLAG_FIXED_NEWSTYLE)
		negotiationflags |= NBD_FLAG_C_FIXED_NEWSTYLE;
	else if (keyfile) {
		snprintf(errstr, errstr_len, "Cannot negotiate TLS without NBD_FLAG_FIXED_NEWSTYLE");
		goto err;
	}
	negotiationflags = htonl(negotiationflags);
	WRITE_ALL_ERRCHK(sock, &negotiationflags, sizeof(negotiationflags), err,
			 "Could not write reserved field: %s", strerror(errno));
	if (testflags & TEST_HANDSHAKE) {
		/* Server must support newstyle for this test */
		if (!(handshakeflags & NBD_FLAG_FIXED_NEWSTYLE)) {
			strncpy(errstr, "server does not support handshake", errstr_len);
			goto err;
		}
		goto end;
	}
#if HAVE_GNUTLS
	/* TLS */
	if (keyfile) {
		int plainfd[2]; // [0] is used by the proxy, [1] is used by NBD
		tlssession_t *s = NULL;
		int ret;

		/* magic */
		tmp64 = htonll(opts_magic);
		WRITE_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
				 "Could not write magic: %s", strerror(errno));
		/* starttls */
		tmp32 = htonl(NBD_OPT_STARTTLS);
		WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
			 "Could not write option: %s", strerror(errno));
		/* length of data */
		tmp32 = htonl(0);
		WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
			 "Could not write option length: %s", strerror(errno));

		READ_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
				"Could not read cliserv_magic: %s", strerror(errno));
		tmp64 = ntohll(tmp64);
		if (tmp64 != NBD_OPT_REPLY_MAGIC) {
			strncpy(errstr, "reply magic does not match", errstr_len);
			goto err;
		}
		READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
				"Could not read option type: %s", strerror(errno));
		tmp32 = ntohl(tmp32);
		if (tmp32 != NBD_OPT_STARTTLS) {
			strncpy(errstr, "Reply to wrong option", errstr_len);
			goto err;
		}
		READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
				"Could not read option reply type: %s", strerror(errno));
		tmp32 = ntohl(tmp32);
		if (tmp32 != NBD_REP_ACK) {
			if(tmp32 & NBD_REP_FLAG_ERROR) {
				snprintf(errstr, errstr_len, "Received error %d", tmp32 & ~NBD_REP_FLAG_ERROR);
			} else {
				snprintf(errstr, errstr_len, "Option reply type %d != NBD_REP_ACK", tmp32);
			}
			goto err;
		}
		READ_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
				"Could not read option data length: %s", strerror(errno));
		tmp32 = ntohl(tmp32);
		if (tmp32 != 0) {
			strncpy(errstr, "Option reply data length != 0", errstr_len);
			goto err;
		}

		s = tlssession_new(FALSE,
				   keyfile,
				   certfile,
				   cacertfile,
				   tlshostname,
				   !cacertfile || !tlshostname, // insecure flag
#ifdef DODBG
				   1, // debug
#else
				   0, // debug
#endif
				   NULL, // quitfn
				   tlserrout, // erroutfn
				   NULL // opaque
			);
		if (!s) {
			strncpy(errstr, "Cannot establish TLS session", errstr_len);
			goto err;
		}

		if (socketpair(AF_UNIX, SOCK_STREAM, 0, plainfd) < 0) {
			strncpy(errstr, "Cannot get socket pair", errstr_len);
			goto err;
		}

		if (set_nonblocking(plainfd[0], 0) <0 ||
		    set_nonblocking(plainfd[1], 0) <0 ||
		    set_nonblocking(sock, 0) <0) {
			close(plainfd[0]);
			close(plainfd[1]);
			strncpy(errstr, "Cannot set socket options", errstr_len);
			goto err;
		}

		ret = fork();
		if (ret < 0)
			err("Could not fork");
		else if (ret == 0) {
			// we are the child
			signal (SIGPIPE, SIG_IGN);
			close(plainfd[1]);
			tlssession_mainloop(sock, plainfd[0], s);
			close(sock);
			close(plainfd[0]);
			exit(0);
		}
		close(plainfd[0]);
		close(sock);
		sock = plainfd[1]; /* use the decrypted FD from now on */
	}
#else
	if (keyfile) {
		strncpy(errstr, "TLS requested but support not compiled in", errstr_len);
		goto err;
	}
#endif
	if(testflags & TEST_EXPECT_ERROR) {
		struct sigaction act;
		memset(&act, '0', sizeof act);
		act.sa_handler = SIG_IGN;
		sigaction(SIGPIPE, &act, NULL);
	}
	/* magic */
	tmp64 = htonll(opts_magic);
	WRITE_ALL_ERRCHK(sock, &tmp64, sizeof(tmp64), err,
			 "Could not write magic: %s", strerror(errno));
	/* name */
	tmp32 = htonl(NBD_OPT_EXPORT_NAME);
	WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
			 "Could not write option: %s", strerror(errno));
	tmp32 = htonl((uint32_t) strlen(name));
	WRITE_ALL_ERRCHK(sock, &tmp32, sizeof(tmp32), err,
			 "Could not write name length: %s", strerror(errno));
	WRITE_ALL_ERRCHK(sock, name, strlen(name), err,
			 "Could not write name:: %s", strerror(errno));
	READ_ALL_ERRCHK(sock, &size, sizeof(size), err,
			"Could not read size: %s", strerror(errno));
	size = ntohll(size);
	uint16_t flags;
	READ_ALL_ERRCHK(sock, &flags, sizeof(uint16_t), err,
			"Could not read flags: %s", strerror(errno));
	flags = ntohs(flags);
	*serverflags = flags;
	READ_ALL_ERRCHK(sock, buf, 124, err,
			"Could not read reserved zeroes: %s", strerror(errno));
	goto end;
err:
	close(sock);
	sock = -1;
end:
	return sock;
}