Complete.Org: Mailing Lists: Archives: freeciv-dev: November 2004:
[Freeciv-Dev] (PR#10727) [PATCH] Hack challenge protocol issues.
Home

[Freeciv-Dev] (PR#10727) [PATCH] Hack challenge protocol issues.

[Top] [All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index] [Thread Index]
Subject: [Freeciv-Dev] (PR#10727) [PATCH] Hack challenge protocol issues.
From: "Vasco Alexandre da Silva Costa" <vasc@xxxxxxxxxxxxxx>
Date: Mon, 15 Nov 2004 15:46:32 -0800
Reply-to: rt@xxxxxxxxxxx

<URL: http://rt.freeciv.org/Ticket/Display.html?id=10727 >

Like hack-4, but uses challenge_$PORT_$CONNECTION_ID as the filename so
you can run multiple servers with the same user without a problem.



Index: client/connectdlg_common.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/connectdlg_common.c,v
retrieving revision 1.26
diff -u -r1.26 connectdlg_common.c
--- client/connectdlg_common.c  24 Oct 2004 23:18:07 -0000      1.26
+++ client/connectdlg_common.c  15 Nov 2004 23:45:25 -0000
@@ -37,7 +37,9 @@
 #include <sys/wait.h>
 #endif
 
+#include "capability.h"
 #include "fcintl.h"
+#include "log.h"
 #include "mem.h"
 #include "netintf.h"
 #include "rand.h"
@@ -67,6 +69,7 @@
 char player_name[MAX_LEN_NAME];
 char *current_filename = NULL;
 
+static char challenge_fullname[MAX_LEN_PATH];
 static bool client_has_hack = FALSE;
 
 int internal_server_port;
@@ -369,33 +372,58 @@
 #endif
 }
 
+/*************************************************************************
+  generate a random string.
+*************************************************************************/
+static void randomize_string(char *str, size_t n)
+{
+  const char chars[] =
+    "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+  int i;
+
+  for (i = 0; i < n - 1; i++) {
+    str[i] = chars[myrand(sizeof(chars) - 1)];
+  }
+  str[i] = '\0';
+}
+
 /**************************************************************** 
 if the client is capable of 'wanting hack', then the server will 
 send the client a filename in the packet_join_game_reply packet.
 
-this function creates the file with a suitably random number in it 
-and then sends the filename and number to the server. If the server 
-can open and read the number, then the client is given hack access.
+this function creates the file with a suitably random string in it 
+and then sends the string to the server. If the server can open
+and read the string, then the client is given hack access.
 *****************************************************************/ 
-void send_client_wants_hack(char * filename)
+void send_client_wants_hack(const char *filename)
 {
-  struct section_file file;
-
-  /* find some entropy */ 
-  int entropy = myrand(MAX_UINT32) - time(NULL);
+  if (has_capability("new_hack", aconnection.capability)) {
+    if (filename[0] != '\0') {
+      struct packet_single_want_hack_req req;
+      struct section_file file;
+
+      /* generate an authentication token */ 
+      randomize_string(req.token, sizeof(req.token));
+
+      /* get the full filename path */
+      interpret_tilde(challenge_fullname, sizeof(challenge_fullname),
+         "~/.freeciv/");
+      make_dir(challenge_fullname);
+
+      sz_strlcat(challenge_fullname, filename);
+
+      section_file_init(&file);
+      secfile_insert_str(&file, req.token, "challenge.token");
+      if (!section_file_save(&file, challenge_fullname, 0)) {
+       freelog(LOG_ERROR, "Couldn't write token to temporary file: %s",
+           challenge_fullname);
+      }
+      section_file_free(&file);
 
-  /* we don't want zero */ 
-  if (entropy == 0) {
-    entropy++;
+      /* tell the server what we put into the file */ 
+      send_packet_single_want_hack_req(&aconnection, &req);
+    }
   }
-
-  section_file_init(&file);
-  secfile_insert_int(&file, entropy, "challenge.entropy");
-  section_file_save(&file, filename, 0);      
-  section_file_free(&file);
-
-  /* tell the server what we put into the file */ 
-  dsend_packet_single_want_hack_req(&aconnection, entropy);
 }
 
 /**************************************************************** 
@@ -403,6 +431,17 @@
 *****************************************************************/ 
 void handle_single_want_hack_reply(bool you_have_hack)
 {
+  if (has_capability("new_hack", aconnection.capability)) {
+    /* remove challenge file */
+    if (challenge_fullname[0] != '\0') {
+      if (remove(challenge_fullname) == -1) {
+       freelog(LOG_ERROR, "Couldn't remove temporary file: %s",
+           challenge_fullname);
+      }
+      challenge_fullname[0] = '\0';
+    }
+  }
+
   if (you_have_hack) {
     append_output_window(_("We have control of the server "
                          "(command access level hack)"));
Index: client/connectdlg_common.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/client/connectdlg_common.h,v
retrieving revision 1.6
diff -u -r1.6 connectdlg_common.h
--- client/connectdlg_common.h  21 Aug 2004 16:34:03 -0000      1.6
+++ client/connectdlg_common.h  15 Nov 2004 23:45:25 -0000
@@ -25,7 +25,7 @@
 bool is_server_running(void);
 bool can_client_access_hack(void);
 
-void send_client_wants_hack(char *filename);
+void send_client_wants_hack(const char *filename);
 void send_start_saved_game(void);
 void send_save_game(char *filename);
 
Index: common/capstr.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/capstr.c,v
retrieving revision 1.194
diff -u -r1.194 capstr.c
--- common/capstr.c     4 Nov 2004 03:02:10 -0000       1.194
+++ common/capstr.c     15 Nov 2004 23:45:25 -0000
@@ -90,7 +90,7 @@
  *     as long as possible.  We want to maintain network compatibility with
  *     the stable branch for as long as possible.
  */
-#define CAPABILITY "+2.0 connecting conn_ping_info username_info"
+#define CAPABILITY "+2.0 connecting conn_ping_info username_info new_hack"
 
 void init_our_capability(void)
 {
Index: common/packets.def
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets.def,v
retrieving revision 1.58
diff -u -r1.58 packets.def
--- common/packets.def  4 Nov 2004 03:02:10 -0000       1.58
+++ common/packets.def  15 Nov 2004 23:45:26 -0000
@@ -1254,8 +1254,9 @@
 /*********************************************************
  Below are the packets that control single-player mode.  
 *********************************************************/
-PACKET_SINGLE_WANT_HACK_REQ=108;cs,handle-per-conn,no-handle,dsend
- UINT32 challenge;
+PACKET_SINGLE_WANT_HACK_REQ=108;cs,handle-per-conn,no-handle
+ UINT32 old_token; remove-cap(new_hack)
+ STRING token[MAX_LEN_NAME]; add-cap(new_hack)
 end
 
 PACKET_SINGLE_WANT_HACK_REPLY=109;sc,dsend
Index: common/packets_gen.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets_gen.c,v
retrieving revision 1.60
diff -u -r1.60 packets_gen.c
--- common/packets_gen.c        4 Nov 2004 03:02:10 -0000       1.60
+++ common/packets_gen.c        15 Nov 2004 23:45:31 -0000
@@ -27081,11 +27081,102 @@
   }
 
   if (BV_ISSET(fields, 0)) {
+    dio_get_string(&din, real_packet->token, sizeof(real_packet->token));
+  }
+
+  clone = fc_malloc(sizeof(*clone));
+  *clone = *real_packet;
+  if (old) {
+    free(old);
+  }
+  hash_insert(*hash, clone, clone);
+
+  RECEIVE_PACKET_END(real_packet);
+}
+
+static int send_packet_single_want_hack_req_100(struct connection *pc, const 
struct packet_single_want_hack_req *packet)
+{
+  const struct packet_single_want_hack_req *real_packet = packet;
+  packet_single_want_hack_req_100_fields fields;
+  struct packet_single_want_hack_req *old, *clone;
+  bool differ, old_from_hash, force_send_of_unchanged = TRUE;
+  struct hash_table **hash = &pc->phs.sent[PACKET_SINGLE_WANT_HACK_REQ];
+  int different = 0;
+  SEND_PACKET_START(PACKET_SINGLE_WANT_HACK_REQ);
+
+  if (!*hash) {
+    *hash = hash_new(hash_packet_single_want_hack_req_100, 
cmp_packet_single_want_hack_req_100);
+  }
+  BV_CLR_ALL(fields);
+
+  old = hash_lookup_data(*hash, real_packet);
+  old_from_hash = (old != NULL);
+  if (!old) {
+    old = fc_malloc(sizeof(*old));
+    memset(old, 0, sizeof(*old));
+    force_send_of_unchanged = TRUE;
+  }
+
+  differ = (strcmp(old->token, real_packet->token) != 0);
+  if(differ) {different++;}
+  if(differ) {BV_SET(fields, 0);}
+
+  if (different == 0 && !force_send_of_unchanged) {
+    return 0;
+  }
+
+  DIO_BV_PUT(&dout, fields);
+
+  if (BV_ISSET(fields, 0)) {
+    dio_put_string(&dout, real_packet->token);
+  }
+
+
+  if (old_from_hash) {
+    hash_delete_entry(*hash, old);
+  }
+
+  clone = old;
+
+  *clone = *real_packet;
+  hash_insert(*hash, clone, clone);
+  SEND_PACKET_END;
+}
+
+#define hash_packet_single_want_hack_req_101 hash_const
+
+#define cmp_packet_single_want_hack_req_101 cmp_const
+
+BV_DEFINE(packet_single_want_hack_req_101_fields, 1);
+
+static struct packet_single_want_hack_req 
*receive_packet_single_want_hack_req_101(struct connection *pc, enum 
packet_type type)
+{
+  packet_single_want_hack_req_101_fields fields;
+  struct packet_single_want_hack_req *old;
+  struct hash_table **hash = &pc->phs.received[type];
+  struct packet_single_want_hack_req *clone;
+  RECEIVE_PACKET_START(packet_single_want_hack_req, real_packet);
+
+  DIO_BV_GET(&din, fields);
+
+
+  if (!*hash) {
+    *hash = hash_new(hash_packet_single_want_hack_req_101, 
cmp_packet_single_want_hack_req_101);
+  }
+  old = hash_delete_entry(*hash, real_packet);
+
+  if (old) {
+    *real_packet = *old;
+  } else {
+    memset(real_packet, 0, sizeof(*real_packet));
+  }
+
+  if (BV_ISSET(fields, 0)) {
     {
       int readin;
     
       dio_get_uint32(&din, &readin);
-      real_packet->challenge = readin;
+      real_packet->old_token = readin;
     }
   }
 
@@ -27099,10 +27190,10 @@
   RECEIVE_PACKET_END(real_packet);
 }
 
-static int send_packet_single_want_hack_req_100(struct connection *pc, const 
struct packet_single_want_hack_req *packet)
+static int send_packet_single_want_hack_req_101(struct connection *pc, const 
struct packet_single_want_hack_req *packet)
 {
   const struct packet_single_want_hack_req *real_packet = packet;
-  packet_single_want_hack_req_100_fields fields;
+  packet_single_want_hack_req_101_fields fields;
   struct packet_single_want_hack_req *old, *clone;
   bool differ, old_from_hash, force_send_of_unchanged = TRUE;
   struct hash_table **hash = &pc->phs.sent[PACKET_SINGLE_WANT_HACK_REQ];
@@ -27110,7 +27201,7 @@
   SEND_PACKET_START(PACKET_SINGLE_WANT_HACK_REQ);
 
   if (!*hash) {
-    *hash = hash_new(hash_packet_single_want_hack_req_100, 
cmp_packet_single_want_hack_req_100);
+    *hash = hash_new(hash_packet_single_want_hack_req_101, 
cmp_packet_single_want_hack_req_101);
   }
   BV_CLR_ALL(fields);
 
@@ -27122,7 +27213,7 @@
     force_send_of_unchanged = TRUE;
   }
 
-  differ = (old->challenge != real_packet->challenge);
+  differ = (old->old_token != real_packet->old_token);
   if(differ) {different++;}
   if(differ) {BV_SET(fields, 0);}
 
@@ -27133,7 +27224,7 @@
   DIO_BV_PUT(&dout, fields);
 
   if (BV_ISSET(fields, 0)) {
-    dio_put_uint32(&dout, real_packet->challenge);
+    dio_put_uint32(&dout, real_packet->old_token);
   }
 
 
@@ -27157,8 +27248,10 @@
   }
 
   if(FALSE) {
-  } else if(TRUE) {
+  } else if((has_capability("new_hack", pc->capability) && 
has_capability("new_hack", our_capability))) {
     variant = 100;
+  } else if(!(has_capability("new_hack", pc->capability) && 
has_capability("new_hack", our_capability))) {
+    variant = 101;
   } else {
     die("unknown variant");
   }
@@ -27181,6 +27274,7 @@
 
   switch(pc->phs.variant[PACKET_SINGLE_WANT_HACK_REQ]) {
     case 100: return receive_packet_single_want_hack_req_100(pc, type);
+    case 101: return receive_packet_single_want_hack_req_101(pc, type);
     default: die("unknown variant"); return NULL;
   }
 }
@@ -27201,19 +27295,11 @@
 
   switch(pc->phs.variant[PACKET_SINGLE_WANT_HACK_REQ]) {
     case 100: return send_packet_single_want_hack_req_100(pc, packet);
+    case 101: return send_packet_single_want_hack_req_101(pc, packet);
     default: die("unknown variant"); return -1;
   }
 }
 
-int dsend_packet_single_want_hack_req(struct connection *pc, int challenge)
-{
-  struct packet_single_want_hack_req packet, *real_packet = &packet;
-
-  real_packet->challenge = challenge;
-  
-  return send_packet_single_want_hack_req(pc, real_packet);
-}
-
 #define hash_packet_single_want_hack_reply_100 hash_const
 
 #define cmp_packet_single_want_hack_reply_100 cmp_const
Index: common/packets_gen.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/common/packets_gen.h,v
retrieving revision 1.51
diff -u -r1.51 packets_gen.h
--- common/packets_gen.h        4 Nov 2004 03:02:11 -0000       1.51
+++ common/packets_gen.h        15 Nov 2004 23:45:32 -0000
@@ -979,7 +979,8 @@
 };
 
 struct packet_single_want_hack_req {
-  int challenge;
+  int old_token;
+  char token[MAX_LEN_NAME];
 };
 
 struct packet_single_want_hack_reply {
@@ -1600,7 +1601,6 @@
 
 struct packet_single_want_hack_req *receive_packet_single_want_hack_req(struct 
connection *pc, enum packet_type type);
 int send_packet_single_want_hack_req(struct connection *pc, const struct 
packet_single_want_hack_req *packet);
-int dsend_packet_single_want_hack_req(struct connection *pc, int challenge);
 
 struct packet_single_want_hack_reply 
*receive_packet_single_want_hack_reply(struct connection *pc, enum packet_type 
type);
 int send_packet_single_want_hack_reply(struct connection *pc, const struct 
packet_single_want_hack_reply *packet);
Index: server/connecthand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/connecthand.c,v
retrieving revision 1.35
diff -u -r1.35 connecthand.c
--- server/connecthand.c        23 Oct 2004 23:12:22 -0000      1.35
+++ server/connecthand.c        15 Nov 2004 23:45:35 -0000
@@ -82,7 +82,7 @@
   sz_strlcpy(packet.capability, our_capability);
   my_snprintf(packet.message, sizeof(packet.message), _("%s Welcome"),
               pconn->username);
-  sz_strlcpy(packet.challenge_file, create_challenge_filename());
+  sz_strlcpy(packet.challenge_file, new_challenge_filename(pconn));
   packet.conn_id = pconn->id;
   send_packet_server_join_reply(pconn, &packet);
 
Index: server/gamehand.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/gamehand.c,v
retrieving revision 1.144
diff -u -r1.144 gamehand.c
--- server/gamehand.c   10 Oct 2004 20:02:02 -0000      1.144
+++ server/gamehand.c   15 Nov 2004 23:45:35 -0000
@@ -18,6 +18,7 @@
 #include <assert.h>
 #include <stdio.h> /* for remove() */ 
 
+#include "capability.h"
 #include "events.h"
 #include "fcintl.h"
 #include "improvement.h"
@@ -34,15 +35,10 @@
 #include "unittools.h"
 
 #include "gamehand.h"
+#include "srv_main.h"
 
-#define NUMBER_OF_TRIES 500
-#ifndef __VMS
-#  define CHALLENGE_ROOT ".freeciv-tmp"
-#else /*VMS*/
-#  define CHALLENGE_ROOT "freeciv-tmp"
-#endif
+#define CHALLENGE_ROOT "challenge"
 
-static char challenge_filename[MAX_LEN_PATH];
 
 /****************************************************************************
   Initialize the game.id variable to a random string of characters.
@@ -413,74 +409,79 @@
 }
 
 /************************************************************************** 
-find a suitably random file that we can write too, and return it's name.
+  generate challenge filename for this connection, cannot fail.
 **************************************************************************/
-const char *create_challenge_filename(void)
+static void gen_challenge_filename(struct connection *pc)
 {
-  int i;
-  unsigned int tmp = 0;
+}
 
-  /* find a suitable file to place the challenge in, we'll remove the file
-   * once the challenge is  */
-#ifndef CHALLENGE_PATH
-  sz_strlcpy(challenge_filename, user_home_dir());
-  sz_strlcat(challenge_filename, "/");
-  sz_strlcat(challenge_filename, CHALLENGE_ROOT);
-#else
-  sz_strlcpy(challenge_filename, CHALLENGE_PATH);
-#endif
-
-  for (i = 0; i < NUMBER_OF_TRIES; i++) {
-    char test_str[MAX_LEN_PATH];
-
-    sz_strlcpy(test_str, challenge_filename);
-    tmp = time(NULL);
-    cat_snprintf(test_str, MAX_LEN_PATH, "-%d", tmp);
-
-    /* file doesn't exist but we can create one and write to it */
-    if (!is_reg_file_for_access(test_str, FALSE) &&
-        is_reg_file_for_access(test_str, TRUE)) {
-      cat_snprintf(challenge_filename, MAX_LEN_PATH, "-%d", tmp);
-      break;
-    } else {
-      die("we can't seem to write to the filesystem!");
-    }
+/************************************************************************** 
+  get challenge filename for this connection.
+**************************************************************************/
+static const char *get_challenge_filename(struct connection *pc)
+{
+  static char filename[MAX_LEN_PATH];
+
+  my_snprintf(filename, sizeof(filename), "%s_%d_%d",
+      CHALLENGE_ROOT, srvarg.port, pc->id);
+
+  return filename;
+}
+
+/************************************************************************** 
+  get challenge full filename for this connection.
+**************************************************************************/
+static const char *get_challenge_fullname(struct connection *pc)
+{
+  static char fullname[MAX_LEN_PATH];
+
+  interpret_tilde(fullname, sizeof(fullname), "~/.freeciv/");
+  sz_strlcat(fullname, get_challenge_filename(pc));
+
+  return fullname;
+}
+
+/************************************************************************** 
+  find a file that we can write too, and return it's name.
+**************************************************************************/
+const char *new_challenge_filename(struct connection *pc)
+{
+  if (!has_capability("new_hack", pc->capability)) {
+    return "";
   }
 
-  return challenge_filename;
+  gen_challenge_filename(pc);
+  return get_challenge_filename(pc);
 }
 
+
 /************************************************************************** 
 opens a file specified by the packet and compares the packet values with
 the file values. Sends an answer to the client once it's done.
 **************************************************************************/
-void handle_single_want_hack_req(struct connection *pc, int challenge)
+void handle_single_want_hack_req(struct connection *pc,
+                                const struct packet_single_want_hack_req
+                                *packet)
 {
   struct section_file file;
-  int entropy = 0;
-  bool could_load = TRUE;
+  char *token = NULL;
   bool you_have_hack = FALSE;
 
-  if (is_reg_file_for_access(challenge_filename, FALSE)) {
-    if (section_file_load_nodup(&file, challenge_filename)) {
-      entropy = secfile_lookup_int_default(&file, 0, "challenge.entropy");
-      section_file_free(&file);
-    } else {
-      freelog(LOG_ERROR, "couldn't load temporary file: %s",
-              challenge_filename);
-      could_load = FALSE;
-    }
+  if (!has_capability("new_hack", pc->capability)) {
+    dsend_packet_single_want_hack_reply(pc, FALSE);
+    return ;
+  }
 
-    /* remove temp file */
-    if (remove(challenge_filename) != 0) {
-      freelog(LOG_ERROR, "couldn't remove temporary file: %s",
-              challenge_filename);
-    }
-  } else {
-    could_load = FALSE;
+  if (section_file_load_nodup(&file, get_challenge_fullname(pc))) {
+    token = secfile_lookup_str_default(&file, NULL, "challenge.token");
+    section_file_free(&file);
+  }
+
+  if (!token) {
+    freelog(LOG_DEBUG, "Failed to read authentication token");
   }
 
-  you_have_hack = (could_load && entropy && entropy == challenge);
+  you_have_hack = (token && strcmp(token, packet->token) == 0);
 
   if (you_have_hack) {
     pc->access_level = ALLOW_HACK;
Index: server/gamehand.h
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/gamehand.h,v
retrieving revision 1.11
diff -u -r1.11 gamehand.h
--- server/gamehand.h   10 Apr 2004 03:47:49 -0000      1.11
+++ server/gamehand.h   15 Nov 2004 23:45:35 -0000
@@ -25,7 +25,12 @@
 
 int update_timeout(void);
 
-const char *create_challenge_filename(void);
-void handle_single_want_hack_req(struct connection *pc, int challenge);
+const char *new_challenge_filename(struct connection *pc);
+
+struct packet_single_want_hack_req;
+
+void handle_single_want_hack_req(struct connection *pc,
+                                const struct packet_single_want_hack_req
+                                *packet);
 
 #endif  /* FC__GAMEHAND_H */
Index: server/srv_main.c
===================================================================
RCS file: /home/freeciv/CVS/freeciv/server/srv_main.c,v
retrieving revision 1.208
diff -u -r1.208 srv_main.c
--- server/srv_main.c   11 Nov 2004 16:56:39 -0000      1.208
+++ server/srv_main.c   15 Nov 2004 23:45:40 -0000
@@ -952,7 +952,7 @@
 
   if (type == PACKET_SINGLE_WANT_HACK_REQ) {
     handle_single_want_hack_req(pconn,
-               ((struct packet_single_want_hack_req *)packet)->challenge);
+                               (struct packet_single_want_hack_req *) packet);
     return TRUE;
   }
 

[Prev in Thread] Current Thread [Next in Thread]