changeset 24:ce26225f7d9d

Switch to the Git version of dgamelaunch.
author John "Elwin" Edwards
date Sun, 20 Oct 2013 17:45:38 -0700
parents 070a9ced4d3e
children dd72d2dd923f
files README.txt dgl/dgamelaunch.conf dgl/dgl-common.c.patch dgl/rlgwebd-compat.patch
diffstat 4 files changed, 362 insertions(+), 113 deletions(-) [+]
line wrap: on
line diff
--- a/README.txt	Sat Oct 05 17:10:24 2013 -0700
+++ b/README.txt	Sun Oct 20 17:45:38 2013 -0700
@@ -1,8 +1,8 @@
 RLG: various files used by the Roguelike Gallery.
 
 dgl/ contains the Gallery's dgamelaunch.conf file, the dgamelaunch menus, and 
-a patch to dgamelaunch 1.5.1 which makes it compatible with the RLGWebD 
-player.
+a patch to the Git version of dgamelaunch.  The patch makes it compatible with 
+the RLGWebD player and adds properly salted passwords.
 
 py/ contains various Python scripts.
 
--- a/dgl/dgamelaunch.conf	Sat Oct 05 17:10:24 2013 -0700
+++ b/dgl/dgamelaunch.conf	Sun Oct 20 17:45:38 2013 -0700
@@ -1,4 +1,7 @@
-# rlgallery.org configuration file for dgamelaunch
+# This is a sample dgamelaunch configuration file. Only bash-style comments
+# are allowed, such as this. Each configuration option will be explained
+# along with its default value.
+
 
 
 # Global config variables:
@@ -6,7 +9,7 @@
 
 # Max amount of registered users to allow. Has no effect if dgl was
 # compiled with SQLite
-maxusers = 4096
+maxusers = 64000
 
 # Allow registration of new nicks? (yes or no)
 allow_new_nicks = yes
@@ -17,23 +20,48 @@
 maxnicklen = 10
 
 # Set the default watching-screen sorting mode. Can be one of
-# "unsorted", "username" or "idletime".  Unsorted is the default.
+# "username", "game", "windowsize", "starttime" or "idletime".
+# "username" is the default.
 sortmode = "username"
 
+# Set the columns displayed in the watching-screen. Each column definition
+# must have four elements as:
+#   [ "<display title>", "<sortname>", <Screen column>, "<printf format>" ]
+#
+# <sortname> may be "unsorted", "username", "game", "windowsize", "starttime",
+# "duration", "idletime", or (if shmem is enabled) "watchers".
+#
+watch_columns = [ ["", "", 1, "%s)"],
+                  ["User", "username", 4, "%-15s"],
+                  ["Game", "game", 21, "%-11s"],
+                  ["Term", "windowsize", 34, "%s"],
+                  ["Idle", "idletime", 43, "%-10s"],
+                  ["Started", "starttime", 60, "%s"]
+                ]
+
 # Path to a prepared chroot jail.
-chroot_path = "/var/dgl/"
+chroot_path = "/var/dgl"
 
 # From inside the jail, dgamelaunch's working directory for rcfiles/ttyrec/etc
 dglroot = "/dgldir/"
 
-# Server ID string
-server_id = "Roguelike Gallery - rlgallery.org"
+# Strings to be replaced in every banner
+# you can have either direct string replacements, like
+# "$FOO" = "BAR", or you can get the server time with
+# "$FOO" = timeformat("%F %T")
+# for the timeformat parameter string format, see man strftime
+bannervars = [ "$MOTDTIME" = "2011.10.08",
+	       "$SERVERID" = "$ATTR(14)Roguelike Gallery - rlgallery.org$ATTR()",
+	       "$DATETIME" = timeformat("%F %T")
+	     ]
 
-# From inside the jail, location of a banner file, the topmost line will be
+# From inside the jail, location of a banner file, which is
 # shown in submenus that cannot be defined separately.
-# Some string substitution is done for the file:
-# $VERSION   replaced with "dgamelaunch v" + dgl version number.
-# $SERVERID  replaced with the server_id string, as defined above.
+# Some string substitution is done for every banner file contents:
+# - bannervars from above
+# - $VERSION replaced with "dgamelaunch v" + dgl version number.
+# - $USERNAME replaced with logged-in user's name, or with "[Anonymous]"
+# - $INCLUDE(filename) the named file will be inserted here.
 banner = "/dgldir/dgl-banner"
 
 # The following two options are fairly insecure. They will force us to
@@ -51,17 +79,39 @@
 #shed_group = "games"
 
 # Preferably, you may use the respective gids/uids. This is for Debian:
-# Use the rodney account instead of games:games
 shed_uid = 501
 shed_gid = 501
 
-# The defaults are usually just fine for this. passwd refers to the file
-# that stores the user database, and lockfile is only used internally by
-# dgamelaunch.
-# passwd doesn't matter if dgl was compiled with SQLite, as the name of
-# the sqlite database will be defined at compile time.
-passwd = "/dgldir/dgl-login"
-lockfile = "/dgldir/dgl-lock"
+# Locale. Leaving this out, dgamelaunch will not explicitly set locale.
+locale = "en_US.UTF-8"
+
+# Default TERM, used if the user's $TERM is unknown.
+# If undefined, dgamelaunch will just terminate in that case.
+default_term = "xterm"
+
+# Should dgl send select-UTF8-charset escape code? (that is: ESC % G)
+# default is no.
+#utf8esc = yes
+
+# Should dgl allow XON/XOFF? Default is "yes", meaning "don't touch it".
+# "no" disables XON/XOFF
+#flowcontrol = no
+
+# Maximum time in seconds user can idle in the dgamelaunch menus
+# before dgl exits. Default value is 0, which disables the idling timer.
+# Does not apply to external programs or config editors.
+# For setting game idle time, use max_idle_time in the game DEFINE.
+# menu_max_idle_time = 1024
+
+# Passwd refers to the file that stores the user database.
+# The default passwd file is "/dgl-login" for flat-text database, and for
+# sqlite, whatever value was defined for the sqlite database at compile time.
+# This is also used for the shared memory key, if shmem is enabled at compile
+# time.
+#passwd = "/dgl-login"
+
+# Lockfile is used only when dgl was compiled without sqlite.
+#lockfile = "/dgl-lock"
 
 #
 # define some commands that are run when something happens. format is
@@ -72,6 +122,7 @@
 #   login     = when user has logged in
 #   register  = right after a new user is registered
 #   gamestart = just before a game is started
+#   gameend   = after a game ends (see also per-game "postcommand" define)
 #
 # <command> is:
 #   mkdir "foo"        = create a directory "foo"
@@ -81,6 +132,7 @@
 #   unlink "foo"       = delete file "foo"
 #   setenv "foo" "bar" = set environment variable "foo" to "bar"
 #   exec "foo" "bar"   = execute "foo" with "bar" as it's param
+#   rawprint "foo"     = output string "foo"
 #   chpasswd           = do the change password prompting, if logged in
 #   chmail             = do the change email prompting, if logged in
 #   watch_menu         = go to the watching menu
@@ -88,24 +140,41 @@
 #   ask_login          = do the login prompting, if not logged in
 #   ask_register       = do register new user prompting, if not logged in and
 #                        registration of new nicks is allowed.
-#   edit_options "foo" = edit options for game which has the short name "foo"
-#                        (user must be logged in)
 #   play_game "foo"    = start game which has the short name "foo"
 #                        (user must be logged in)
 #   submenu "foo"      = go to submenu "foo"
 #   return             = return from submenu
 #
+#  NOTE: edit_options-command was removed. use ifnxcp and exec to simulate it.
+#
 # The commands will be done inside the chroot and with the uid and gid
 # defined above.
 # Parameters to the commands are subject to variable substitution:
 #   %r = dglroot, as defined above
 #   %n = user nick, if user is logged in
+#   %N = first character of user name, if user is logged in
 #   %u = shed_uid, as defined above, but numeric
 #   %g = game name, if user has selected a game.
+#   %s = short game name, if user has selected a game.
+#   %t = ttyrec path & filename of the last game played.
+#
+# Also some escape codes:
+#   \\ = backslash
+#   \a = bell
+#   \b = backspace
+#   \e = escape character
+#   \f = form feed
+#   \n = newline
+#   \r = carriage return
+#   \t = tab
+#   \v = vertical tab
 #
 # eg. commands[login] = mkdir "foo", unlink "bar", setenv "Z" "foo"
 #
 
+# Change the terminal title: (assuming terminals support the escape code)
+#commands[dglstart] = rawprint "\e]2;nethack.alt.org\a"
+
 # create the user's dirs when they register
 commands[register] = mkdir "%ruserdata/%n",
                      mkdir "%rttyrec/%n",
@@ -123,6 +192,9 @@
                   mkdir "%rttyrec/%n/srogue",
                   mkdir "%rttyrec/%n/arogue5"
 
+# file mode for when commands copy files.
+# readable and writable by all. you could use eg. "0644" to be more secure.
+filemode = "0644"
 
 
 
@@ -134,6 +206,7 @@
 # First, the menu shown to anonymous user:
 menu["mainmenu_anon"] {
         bannerfile = "/dgldir/dgl_menu_main_anon.txt"
+        cursor = (5,18)
         commands["l"] = ask_login
         commands["r"] = ask_register
         commands["w"] = watch_menu
@@ -145,6 +218,17 @@
 menu["mainmenu_user"] {
 # contents of this file are written to screen.
 # the file must be inside the chroot.
+# Some string subsitutions can be done in the file:
+# $INCLUDE(filename) =  includes the file to this file.
+# String substitutions defined in bannervars-section above.
+# $VERSION           =  dgamelaunch version
+# $USERNAME          =  user name (or [Anonymous] if not logged in)
+# $ATTR(params)      =  change text color and attributes.
+#        params can be either number (to set the text color),
+#	 one, or any of "b" (bold), "s" (standout), "u" (underline),
+#	 "r" (reverse) or "d" (dim),
+#	 or both color number and attribute characters, separated by colon.
+#	 Empty param resets color and attributes to default.
         bannerfile = "/dgldir/dgl_menu_main_user.txt"
 # after which cursor is moved to this location
 # if cursor-definition is missing, the cursor is put
@@ -170,73 +254,6 @@
 	commands["qQ "] = return
 }
 
-
-# Next, we'll define one game's data:
-
-#DEFINE {
-#  # From inside the jail, the location of the binary to be launched.
-#  game_path = "/bin/nethackstub"
-#
-#  # Full name of the game
-#  game_name = "NetHack stub"
-#
-#  # Short name, used in the watching menu
-#  short_name = "NHstb"
-#
-#  # arguments for when we exec the binary
-#  game_args = "/bin/nethackstub",
-#	      "foo",
-#	      "user:%n",
-#	      "shed_uid:%u",
-#	      "bar"
-#
-#  # From inside the jail, where dgamelaunch should put mail.
-#  spooldir = "/var/mail/"
-#
-#  # From inside the jail, the default .nethackrc that is copied for new users.
-#  # rc_template = "/dgl-default-rcfile"
-#
-#  # Make sure the inprogress dir actually exists. default is "inprogress/"
-#  # Each game you define here must have it's own.
-#  inprogressdir = "%rinprogress-nethackstub/"
-#
-#  # We can also define per-game commands, that are executed
-#  # when the game starts:
-#  # commands = chdir "/dgldir", mkdir "foo_%u_%g"
-#}
-
-
-#DEFINE {
-#  game_path = "/nh343/nethack"
-#  game_name = "NetHack 3.4.3"
-#  short_name = "NH343"
-#
-#  game_args = "/nh343/nethack", "-u", "%n"
-#
-#  spooldir = "/mail/"
-#  rc_template = "/dgl-default-rcfile.nh343"
-#
-#  rc_fmt = "%ruserdata/%n/%n.nh343rc"
-#
-#  inprogressdir = "%rinprogress-nh343/"
-#
-## The place where ttyrecs are stored for this game.
-## If this is not defined, ttyrecs are not saved for this game.
-## Leaving this undefined also means the games cannot be spectated.
-#  ttyrecdir = "%ruserdata/%n/ttyrec/"
-#
-#
-#  # back up savefile
-#  commands = cp "/nh343/var/save/%u%n.gz" "/nh343/var/save/%u%n.gz.bak",
-#  # set NETHACKOPTIONS to point to the rcfile
-#             setenv "NETHACKOPTIONS" "@%ruserdata/%n/%n.nh343rc",
-#  # set up nethack mail stuff, assuming it's compiled with it...
-#             setenv "MAIL" "/mail/%n",
-#             setenv "SIMPLEMAIL" "1",
-#  # don't let the mail file grow
-#             unlink "/mail/%n"
-#}
-
 # Rogue V3: short and simple, like the game
 DEFINE {
   game_path = "/bin/rogue3"
@@ -305,3 +322,143 @@
 
   commands = cp "/var/games/roguelike/arogue5save/%u-%n.ar5sav" "%rbackup/%u-%n.ar5sav.bak"
 }
+
+
+# Next, we'll define one game's data:
+
+#DEFINE {
+#  # From inside the jail, the location of the binary to be launched.
+#  game_path = "/bin/nethackstub"
+#
+#  # Full name of the game
+#  game_name = "NetHack stub"
+#
+#  # Short name, used in the watching menu
+#  short_name = "NHstb"
+#
+#  # arguments for when we exec the binary
+#  game_args = "/bin/nethackstub",
+#	      "foo",
+#	      "user:%n",
+#	      "shed_uid:%u",
+#	      "bar"
+#
+#  # From inside the jail, where dgamelaunch should put mail.
+#  spooldir = "/var/mail/"
+#
+#  # From inside the jail, the default .nethackrc that is copied for new users.
+#  # rc_template = "/dgl-default-rcfile"
+#
+#  # If player idles longer than max_idle_time seconds, the game will
+#  # receive a sighup. Default value is 0, which disables the idling timer.
+#  max_idle_time = 2000
+#
+#  # Player-specific path to an extra information file written by the game
+#  # The game should write the extra information on one line in this format:
+#  #    <numeric-weight>|extra-information
+#  # For example, the game might write: "100|Astral", "1|D:1", etc. to indicate
+#  # where the player is in the game world. The numeric weight is used when
+#  # a spectator sorts games by the extra information field: higher weights
+#  # will be sorted to appear before lower weights.
+#  # 
+#  extra_info_file = "%rgamedir/%n.extrainfo"
+#
+#  # Make sure the inprogress dir actually exists. default is "inprogress/"
+#  # Each game you define here must have it's own.
+#  inprogressdir = "%rinprogress-nethackstub/"
+#
+#  # We can also define per-game commands, that are executed
+#  # when the game starts:
+#  # commands = chdir "/dgldir", mkdir "foo_%u_%g"
+#
+#  # We can also define per-game commands executed after the game ends,
+#  # but before commands[gameend]
+#  postcommands = chdir "/"
+#
+#  # If the game uses an ancient encoding, you may specify "ibm" or "dec".
+#  # If set to "ask", the game will be run with --print-charset beforehand,
+#  # expected to return one of these values.
+#  encoding = "unicode"
+#}
+
+
+#
+# the second game
+#
+#
+
+#DEFINE {
+#  game_path = "/nh343/nethack"
+#  game_name = "NetHack 3.4.3"
+#  short_name = "NH343"
+#
+#  game_args = "/nh343/nethack", "-u", "%n"
+#
+#  spooldir = "/mail/"
+#  rc_template = "/dgl-default-rcfile.nh343"
+#
+#  rc_fmt = "%ruserdata/%n/%n.nh343rc"
+#
+#  inprogressdir = "%rinprogress-nh343/"
+#
+## The place where ttyrecs are stored for this game.
+## If this is not defined, ttyrecs are not saved for this game.
+## Leaving this undefined also means the games cannot be spectated.
+#  ttyrecdir = "%ruserdata/%n/ttyrec/"
+#
+#
+#  # back up savefile
+#  commands = cp "/nh343/var/save/%u%n.gz" "/nh343/var/save/%u%n.gz.bak",
+#  # set NETHACKOPTIONS to point to the rcfile
+#             setenv "NETHACKOPTIONS" "@%ruserdata/%n/%n.nh343rc",
+#  # set up nethack mail stuff, assuming it's compiled with it...
+#             setenv "MAIL" "/mail/%n",
+#             setenv "SIMPLEMAIL" "1",
+#  # don't let the mail file grow
+#             unlink "/mail/%n"
+#}
+
+#
+# third game
+#
+#
+
+#DEFINE {
+#  game_path = "/bin/crawlss017"
+#  game_name = "Crawl Stone Soup 0.1.7"
+#  short_name = "Cr017"
+#
+#  game_args = "/bin/crawlss017",
+#	      "-name",   "%n",
+#	      "-dir",    "/crawlss017/",
+#	      "-rc",     "%rrcfiles/%n.crawlrc",
+#	      "-morgue", "/crawlss017/morgues/",
+#	      "-macro",  "/crawlss017/macros/%n.macro"
+#
+#  rc_template = "/dgl-default-rcfile.crawl"
+#  rc_fmt = "%rrcfiles/%n.crawlrc"
+#  inprogressdir = "%rinprogress-crawlss017/"
+#  encoding = ask
+#}
+
+#
+# fourth game
+#
+#
+
+#DEFINE {
+#  game_path = "/bin/crawlss020"
+#  game_name = "Crawl Stone Soup 0.2.0"
+#  short_name = "Cr020"
+#
+#  game_args = "/bin/crawlss020",
+#	      "-name",   "%n",
+#	      "-dir",    "/crawlss020/",
+#	      "-rc",     "/crawlss020/plr/%n/%n.crawlrc",
+#	      "-morgue", "/crawlss020/plr/%n/",
+#	      "-macro",  "/crawlss020/plr/%n/"
+#
+#  rc_template = "/dgl-default-rcfile.crawl"
+#  rc_fmt = "/crawlss020/plr/%n/%n.crawlrc"
+#  inprogressdir = "%rinprogress-crawlss020/"
+#}
--- a/dgl/dgl-common.c.patch	Sat Oct 05 17:10:24 2013 -0700
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,24 +0,0 @@
-504c504
-<   int fd, len, n, is_nhext, pid;
----
->   int fd, len, n, is_nhext, is_node, pid;
-538a539
->       is_node = strchr(pdirent->d_name, ':') && !strncmp(strchr(pdirent->d_name, ':'), ":node:", 6);
-550c551
-<       if (fd >= 0 && (is_nhext || fcntl (fd, F_SETLK, &fl) == -1))
----
->       if (fd >= 0 && (is_nhext || is_node || fcntl (fd, F_SETLK, &fl) == -1))
-567a569,576
->               if (is_node) {
->                   replacestr = strchr(replacestr, ':');
->                   if (!replacestr) {
-> 		      debug_write("inprogress-filename does not have ':', 1a");
-> 		      graceful_exit(145);
-> 	          }
->                   replacestr++;
->               }
-589a599,602
->               if (is_node) {
->                   replacestr++;
->                   replacestr = strchr(replacestr, ':');
->               }
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dgl/rlgwebd-compat.patch	Sun Oct 20 17:45:38 2013 -0700
@@ -0,0 +1,116 @@
+diff --git a/dgamelaunch.c b/dgamelaunch.c
+index fbf6ef5..b52b545 100644
+--- a/dgamelaunch.c
++++ b/dgamelaunch.c
+@@ -1489,7 +1489,10 @@ int
+ changepw (int dowrite)
+ {
+   char buf[DGL_PASSWDLEN+1];
++  char salt[21];
+   int error = 2;
++  int i;
++  FILE *urandom;
+ 
+   /* A precondition is that struct `me' exists because we can be not-yet-logged-in. */
+   if (!me) {
+@@ -1553,8 +1556,28 @@ changepw (int dowrite)
+         error = 1;
+     }
+ 
++  salt[0] = salt[2] = salt[19] = '$';
++  salt[1] = '6';
++  salt[20] = '\0';
++  urandom = fopen("/dev/urandom", "r");
++  for (i = 3; i < 19; i++) {
++    /* This does waste four random bytes. */
++    fread(salt + i, 1, 1, urandom);
++    salt[i] &= 0x3f;
++    if (salt[i] < 26)
++      salt[i] += 'a';
++    else if (salt[i] < 52)
++      salt[i] = 'A' + salt[i] - 26;
++    else if (salt[i] < 62)
++      salt[i] = '0' + salt[i] - 52;
++    else if (salt[i] == 62)
++      salt[i] = '.';
++    else
++      salt[i] = '/';
++  }
++  fclose(urandom);
+   free(me->password);
+-  me->password = strdup (crypt (buf, buf));
++  me->password = strdup (crypt (buf, salt));
+ 
+   if (dowrite)
+     writefile (0);
+@@ -2053,6 +2076,8 @@ passwordgood (char *cpw)
+ {
+   assert (me != NULL);
+ 
++  if (!strncmp (crypt (cpw, me->password), me->password, DGL_PASSWDLEN))
++    return 1;
+   if (!strncmp (crypt (cpw, cpw), me->password, DGL_PASSWDLEN))
+     return 1;
+   if (!strncmp (cpw, me->password, DGL_PASSWDLEN))
+diff --git a/dgamelaunch.h b/dgamelaunch.h
+index b9ce41c..ca5e11b 100644
+--- a/dgamelaunch.h
++++ b/dgamelaunch.h
+@@ -20,7 +20,7 @@
+ #define dglsign(x) (x < 0 ? -1 : (x > 0 ? 1 : 0))
+ 
+ #define DGL_PLAYERNAMELEN 30 /* max. length of player name */
+-#define DGL_PASSWDLEN 20 /* max. length of passwords */
++#define DGL_PASSWDLEN 108 /* max. length of passwords */
+ #define DGL_MAILMSGLEN 80 /* max. length of mail message */
+ 
+ #define DGL_MAXWATCHCOLS 10
+diff --git a/dgl-common.c b/dgl-common.c
+index e5c80bc..fbc4eea 100644
+--- a/dgl-common.c
++++ b/dgl-common.c
+@@ -593,7 +593,7 @@ game_read_extra_info(struct dg_game *game, const char *extra_info_file)
+ struct dg_game **
+ populate_games (int xgame, int *l, struct dg_user *me)
+ {
+-  int fd, len, n, pid;
++  int fd, len, n, pid, is_node;
+   DIR *pdir;
+   struct dirent *pdirent;
+   struct stat pstat;
+@@ -631,13 +631,15 @@ populate_games (int xgame, int *l, struct dg_user *me)
+ 
+       if (!inprog) continue;
+ 
++      is_node = strchr(pdirent->d_name, ':') && !strncmp(strchr(pdirent->d_name, ':'), ":node:", 6);
++
+       snprintf (fullname, 130, "%s%s", inprog, pdirent->d_name);
+ 
+       fd = 0;
+       /* O_RDWR here should be O_RDONLY, but we need to test for
+        * an exclusive lock */
+       fd = open (fullname, O_RDWR);
+-      if (fd >= 0 && (fcntl (fd, F_SETLK, &fl) == -1))
++      if (fd >= 0 && (is_node || (fcntl (fd, F_SETLK, &fl) == -1)))
+         {
+ 		char *ttrecdir = NULL;
+ 		strncpy(playername, pdirent->d_name, DGL_PLAYERNAMELEN);
+@@ -651,6 +653,9 @@ populate_games (int xgame, int *l, struct dg_user *me)
+ 		  graceful_exit(145);
+ 	      }
+               replacestr++;
++              if (is_node) {
++                  replacestr += 5;
++              }
+ 
+ 	      ttrecdir = dgl_format_str(game, me, myconfig[game]->ttyrecdir, playername);
+ 	      if (!ttrecdir) continue;
+@@ -673,6 +678,8 @@ populate_games (int xgame, int *l, struct dg_user *me)
+               strlcpy (games[len]->name, pdirent->d_name,
+                        strlen (pdirent->d_name) + 1);
+ 
++              if (is_node)
++                  replacestr += 5;
+               games[len]->date = malloc (11);
+               strlcpy (games[len]->date, replacestr + 1, 11);
+