diff --git a/network/netplay/README b/network/netplay/README index c9f8c77bbf..a1b5d52e44 100644 --- a/network/netplay/README +++ b/network/netplay/README @@ -159,6 +159,15 @@ Payload: Description: Send nickname. Mandatory handshake command. +Command: PASSWORD +Payload: + { + password hash: char[64] + } +Description: + Send hashed password to server. Mandatory handshake command for clients if + the server demands a password. + Command: SYNC Payload: { diff --git a/network/netplay/netplay_common.c b/network/netplay/netplay_common.c index 48058a4d51..329fa86957 100644 --- a/network/netplay/netplay_common.c +++ b/network/netplay/netplay_common.c @@ -19,6 +19,7 @@ #include "netplay_private.h" #include +#include #include #include @@ -127,8 +128,18 @@ bool netplay_handshake_init_send(netplay_t *netplay, struct netplay_connection * header[1] = htonl(*content_crc_ptr); header[2] = htonl(netplay_platform_magic()); header[3] = htonl(NETPLAY_COMPRESSION_SUPPORTED); - header[4] = htonl((netplay->is_server && netplay->password[0]) ? - NETPLAY_FLAG_PASSWORD_REQUIRED : 0); + if (netplay->is_server && netplay->password[0]) + { + /* Demand a password */ + /* FIXME: Better randomness, or at least seed it */ + connection->salt = rand(); + if (connection->salt == 0) connection->salt = 1; + header[4] = htonl(connection->salt); + } + else + { + header[4] = htonl(0); + } if (!netplay_send(&connection->send_packet_buffer, connection->fd, header, sizeof(header)) || @@ -147,7 +158,7 @@ struct nick_buf_s struct password_buf_s { uint32_t cmd[2]; - char password[128]; + char password[64]; }; #define RECV(buf, sz) \ @@ -163,17 +174,20 @@ static netplay_t *handshake_password_netplay; static void handshake_password(void *ignore, const char *line) { + struct password_buf_s password_buf; + char password[8+128]; /* 8 for salt, 128 for password */ uint32_t cmd[2]; netplay_t *netplay = handshake_password_netplay; struct netplay_connection *connection = &netplay->connections[0]; - memset(netplay->password, 0, sizeof(netplay->password)); - strlcpy(netplay->password, line, sizeof(netplay->password)); - cmd[0] = ntohl(NETPLAY_CMD_PASSWORD); - cmd[1] = ntohl(sizeof(netplay->password)); + snprintf(password, sizeof(password), "%08X", connection->salt); + strlcpy(password + 8, line, sizeof(password)-8); - netplay_send(&connection->send_packet_buffer, connection->fd, cmd, sizeof(cmd)) && - netplay_send(&connection->send_packet_buffer, connection->fd, netplay->password, sizeof(netplay->password)) && + password_buf.cmd[0] = htonl(NETPLAY_CMD_PASSWORD); + password_buf.cmd[1] = htonl(sizeof(password_buf.password)); + sha256_hash(password_buf.password, (uint8_t *) password, strlen(password)); + + netplay_send(&connection->send_packet_buffer, connection->fd, &password_buf, sizeof(password_buf)) && netplay_send_flush(&connection->send_packet_buffer, connection->fd, false); menu_input_dialog_end(); @@ -263,7 +277,7 @@ bool netplay_handshake_init(netplay_t *netplay, struct netplay_connection *conne } /* If a password is demanded, ask for it */ - if (!netplay->is_server && (ntohl(header[4]) & NETPLAY_FLAG_PASSWORD_REQUIRED)) + if (!netplay->is_server && (connection->salt = ntohl(header[4]))) { menu_input_ctx_line_t line; rarch_ctl(RARCH_CTL_MENU_RUNNING, NULL); @@ -441,7 +455,8 @@ bool netplay_handshake_pre_nick(netplay_t *netplay, struct netplay_connection *c bool netplay_handshake_pre_password(netplay_t *netplay, struct netplay_connection *connection, bool *had_input) { - struct password_buf_s password_buf; + struct password_buf_s password_buf, corr_password_buf; + char password[8+128]; /* 8 for salt, 128 for password */ ssize_t recvd; char msg[512]; @@ -449,7 +464,7 @@ bool netplay_handshake_pre_password(netplay_t *netplay, struct netplay_connectio RECV(&password_buf, sizeof(password_buf)); - /* Expecting only a nick command */ + /* Expecting only a password command */ if (recvd < 0 || ntohl(password_buf.cmd[0]) != NETPLAY_CMD_PASSWORD || ntohl(password_buf.cmd[1]) != sizeof(password_buf.password)) @@ -466,7 +481,13 @@ bool netplay_handshake_pre_password(netplay_t *netplay, struct netplay_connectio return false; } - if (strncmp(netplay->password, password_buf.password, sizeof(password_buf.password))) + /* Calculate the correct password */ + snprintf(password, sizeof(password), "%08X", connection->salt); + strlcpy(password + 8, netplay->password, sizeof(password)-8); + sha256_hash(corr_password_buf.password, (uint8_t *) password, strlen(password)); + + /* Compare them */ + if (memcmp(password_buf.password, corr_password_buf.password, sizeof(password_buf.password))) return false; if (!netplay_handshake_sync(netplay, connection)) diff --git a/network/netplay/netplay_private.h b/network/netplay/netplay_private.h index 23f236fca2..1ec14c6f57 100644 --- a/network/netplay/netplay_private.h +++ b/network/netplay/netplay_private.h @@ -79,9 +79,6 @@ #define NETPLAY_COMPRESSION_SUPPORTED 0 #endif -/* Netplay connection flags */ -#define NETPLAY_FLAG_PASSWORD_REQUIRED (1<<0) - enum netplay_cmd { /* Basic commands */ @@ -251,6 +248,9 @@ struct netplay_connection /* Nickname of peer */ char nick[32]; + /* Salt associated with password transaction */ + uint32_t salt; + /* Buffers for sending and receiving data */ struct socket_buffer send_packet_buffer, recv_packet_buffer;