added checking for invalid/malicious packet size in network protocol
[rocksndiamonds.git] / src / netserv.c
index 551772a00c883b5053ddfe00b2925f6bf8ee2b5d..73d35fb32de81a044726b4c0d008a274172cddee 100644 (file)
@@ -187,6 +187,14 @@ static void increaseNetworkBuffer(struct NetworkBuffer *nb, int additional_size)
 int receiveNetworkBufferBytes(struct NetworkBuffer *nb, TCPsocket socket,
                             int num_bytes)
 {
+  if (num_bytes > MAX_PACKET_SIZE)
+  {
+    Error(ERR_NETWORK_SERVER, "protocol error: invalid packet size %d",
+         num_bytes);
+
+    return -1;
+  }
+
   if (nb->pos + num_bytes > nb->max_size)
     increaseNetworkBuffer(nb, num_bytes);
 
@@ -312,6 +320,86 @@ void putNetworkBufferString(struct NetworkBuffer *nb, char *s)
   nb->size = nb->pos;
 }
 
+int getNetworkBufferFile(struct NetworkBuffer *nb, char *filename)
+{
+  FILE *file;
+  int num_bytes = getNetworkBuffer32BitInteger(nb);
+  int i;
+
+  if (!(file = fopen(filename, MODE_WRITE)))
+  {
+    Error(ERR_WARN, "cannot write file '%s' from network buffer", filename);
+
+    return 0;
+  }
+
+  for (i = 0; i < num_bytes; i++)
+  {
+    int b = getNetworkBuffer8BitInteger(nb);
+
+    putFile8Bit(file, b);
+  }
+
+  fclose(file);
+
+  return num_bytes;
+}
+
+int putNetworkBufferFile(struct NetworkBuffer *nb, char *filename)
+{
+  File *file;
+  int filesize_pos = nb->pos;
+  int num_bytes = 0;
+
+  /* will be replaced with file size */
+  putNetworkBuffer32BitInteger(nb, 0);
+
+  if (!(file = openFile(filename, MODE_READ)))
+  {
+    Error(ERR_WARN, "cannot read file '%s' to network buffer", filename);
+
+    return 0;
+  }
+
+  while (1)
+  {
+    int b = getFile8Bit(file);
+
+    if (checkEndOfFile(file))
+      break;
+
+    putNetworkBuffer8BitInteger(nb, b);
+
+    num_bytes++;
+  }
+
+  closeFile(file);
+
+  /* set file size */
+  putNetwork32BitInteger(&nb->buffer[filesize_pos], num_bytes);
+
+  return num_bytes;
+}
+
+void dumpNetworkBuffer(struct NetworkBuffer *nb)
+{
+  int i;
+
+  printf("::: network buffer maximum size: %d\n", nb->max_size);
+  printf("::: network buffer size:         %d\n", nb->size);
+  printf("::: network buffer position    : %d\n", nb->pos);
+
+  for (i = 0; i < nb->size; i++)
+  {
+    if ((i % 16) == 0)
+      printf("\n::: ");
+
+    printf("%02x ", nb->buffer[i]);
+  }
+
+  printf("\n");
+}
+
 static void SendNetworkBufferToAllButOne(struct NetworkBuffer *nb,
                                         struct NetworkServerPlayerInfo *except)
 {
@@ -729,6 +817,13 @@ static void Handle_OP_BROADCAST_MESSAGE(struct NetworkServerPlayerInfo *player)
   SendNetworkBufferToAllButOne(write_buffer, player);
 }
 
+static void Handle_OP_LEVEL_FILE(struct NetworkServerPlayerInfo *player)
+{
+  copyNetworkBufferForWriting(read_buffer, write_buffer, player->number);
+
+  SendNetworkBufferToAllButOne(write_buffer, player);
+}
+
 void ExitNetworkServer(int exit_value)
 {
   Error(ERR_NETWORK_SERVER, "exiting network server");
@@ -927,6 +1022,10 @@ void NetworkServer(int port, int serveronly)
          Handle_OP_BROADCAST_MESSAGE(player);
          break;
 
+       case OP_LEVEL_FILE:
+         Handle_OP_LEVEL_FILE(player);
+         break;
+
        default:
          if (options.verbose)
            Error(ERR_NETWORK_SERVER,