From 545e5e8721920132c9a6aa78d479e8db9816df9b Mon Sep 17 00:00:00 2001 From: Jilles Tjoelker Date: Wed, 21 Apr 2004 16:22:55 +0000 Subject: [PATCH] Merge J. Ali Harlow's patch for NhExt support, with a few changes. Tested a little whether nethack still works. git-svn-id: svn://katsu.triplehelix.org/dgamelaunch/trunk@288 db0b04b0-f4d1-0310-9a6d-de3e77497b0e --- dgamelaunch.8 | 30 ++++++++- dgamelaunch.c | 168 +++++++++++++++++++++++++++++++++++++++++--------- dgl-common.c | 52 +++++++++++----- 3 files changed, 204 insertions(+), 46 deletions(-) diff --git a/dgamelaunch.8 b/dgamelaunch.8 index 8a35c04..87fe2a7 100644 --- a/dgamelaunch.8 +++ b/dgamelaunch.8 @@ -19,14 +19,20 @@ dgamelaunch \- Network console game launcher [ .B \-p ] +[ +.B \-a +] +[ +.B \-e +] .ad .hy 14 .SH DESCRIPTION .PP .I dgamelaunch is a network-based game shell where anyone can sign up for an -account and start playing any game which suits your fancy - currently, though, -it only supports NetHack. +account and start playing any game which suits your fancy - currently +it supports NetHack and Slash'Em. The user is presented with a curses-based menu to watch other games, edit the options or play the game. @@ -42,6 +48,22 @@ Specify the location of the configuration file. Don't print errors pertaining to the server configuration. .TP .B +-a +Enter user authentication mode. +.I +dgamelaunch +will read user name and password from stdin, check them, check whether the +user doesn't have a game in progress already, then write the inprogress lock. +Returns 0 if everything was successful. +.TP +.B +-e +Start game server to handle incoming NhExt connection. +.I +dgamelaunch +will execute /bin/nethack --proxy after chroot and shedding privs. +.TP +.B -p Ignored; solely for compatibility with .B @@ -86,6 +108,8 @@ M. Drew Streib wrote the original version. .PP Later, Joshua Kwan, Brett Carrington and Jilles Tjoelker added many new features. +.PP +NhExt support was written by J. Ali Harlow. .SH FILES .DT .ta \w'dgldir/ttyrec//*.ttyrec\ \ \ 'u @@ -122,7 +146,7 @@ dgldir/ttyrec//*.ttyrec Recorded games, this may get .\".SH ENVIRONMENT .SH "SEE ALSO" .PP -nethack(6), telnetd(8), login(1), curses(3), fcntl(2) +nethack(6), slashem(6), telnetd(8), login(1), curses(3), fcntl(2) .SH BUGS .PP None known. diff --git a/dgamelaunch.c b/dgamelaunch.c index e617aef..767b66b 100644 --- a/dgamelaunch.c +++ b/dgamelaunch.c @@ -165,6 +165,24 @@ gen_ttyrec_filename () /* ************************************************************* */ +char* +gen_nhext_filename () +{ + time_t rawtime; + struct tm *ptm; + char *nhext_filename = calloc(100, sizeof(char)); + + /* append time to filename */ + time (&rawtime); + ptm = gmtime (&rawtime); + snprintf (nhext_filename, 100, "%04i-%02i-%02i.%02i:%02i:%02i.nhext", + ptm->tm_year + 1900, ptm->tm_mon + 1, ptm->tm_mday, + ptm->tm_hour, ptm->tm_min, ptm->tm_sec); + return nhext_filename; +} + +/* ************************************************************* */ + char* gen_inprogress_lock (pid_t pid, char* ttyrec_filename) { @@ -312,7 +330,8 @@ inprogressmenu () int i, menuchoice, len = 20, offset = 0, doresizewin = 0; time_t ctime; struct dg_game **games; - char ttyrecname[130], *replacestr = NULL; + char ttyrecname[130], *replacestr = NULL, gametype[10]; + int is_nhext[14]; sigset_t oldmask, toblock; games = populate_games (&len); @@ -343,9 +362,16 @@ inprogressmenu () if (i + offset >= len) break; - mvprintw (7 + i, 1, "%c) %-15s (%3dx%3d) %s %s (%ldm %lds idle)", - i + 97, games[i + offset]->name, - games[i + offset]->ws_col, games[i + offset]->ws_row, + is_nhext[i] = !strcmp (games[i + offset]->ttyrec_fn + strlen (games[i + offset]->ttyrec_fn) - 6, ".nhext"); + + if (is_nhext[i]) + strcpy (gametype, " NhExt"); + else + snprintf (gametype, sizeof gametype, "%3dx%3d", + games[i + offset]->ws_col, games[i + offset]->ws_row); + + mvprintw (7 + i, 1, "%c) %-15s (%s) %s %s (%ldm %lds idle)", + i + 97, games[i + offset]->name, gametype, games[i + offset]->date, games[i + offset]->time, (time (&ctime) - games[i + offset]->idle_time) / 60, (time (&ctime) - games[i + offset]->idle_time) % 60); @@ -385,6 +411,9 @@ inprogressmenu () } if ((menuchoice - 'a') >= 0 && (menuchoice - 'a') < i) { + if (is_nhext[menuchoice - 97]) /* Cannot watch NhExt game */ + break; + /* valid choice has been made */ snprintf (ttyrecname, 130, "%sttyrec/%s", myconfig->dglroot, games[menuchoice - 97 + offset]->ttyrec_fn); @@ -1561,6 +1590,60 @@ menuloop (void) } } +int +authenticate () +{ + int i, len, me_index; + char user_buf[22], pw_buf[22]; + struct dg_game **games; + + /* We use simple password authentication, rather than challenge/response. */ + printf ("\n"); + fflush(stdout); + + fgets (user_buf, sizeof(user_buf), stdin); + len = strlen (user_buf); + if (user_buf[len - 1] == '\n') + user_buf[--len] = '\0'; + else + { + fprintf (stderr, "Username too long (max 20 chars).\n"); + return 1; + } + + fgets (pw_buf, sizeof(pw_buf), stdin); + len = strlen (pw_buf); + if (pw_buf[len - 1] == '\n') + pw_buf[--len] = '\0'; + else + { + fprintf (stderr, "Password too long (max 20 chars).\n"); + return 1; + } + + if ((me_index = userexist (user_buf)) != -1) + { + me = users[me_index]; + if (passwordgood (pw_buf)) + { + games = populate_games (&len); + for (i = 0; i < len; i++) + if (!strcmp (games[i]->name, user_buf)) + { + fprintf (stderr, "Game already in progress.\n"); + return 1; + } + win.ws_row = win.ws_col = 0; + gen_inprogress_lock (getppid (), gen_nhext_filename ()); + return 0; + } + } + + sleep (2); + fprintf (stderr, "Login failed.\n"); + return 1; +} + int main (int argc, char** argv) { @@ -1568,14 +1651,21 @@ main (int argc, char** argv) char atrcfilename[81], *spool; unsigned int len; int c; + int nhext = 0, nhauth = 0; - while ((c = getopt(argc, argv, "qh:pp:f:")) != -1) + while ((c = getopt(argc, argv, "qh:pp:f:ae")) != -1) { switch (c) { case 'q': silent = 1; break; + case 'a': + nhauth = 1; break; + + case 'e': + nhext = 1; break; + case 'f': if (config) { @@ -1608,37 +1698,54 @@ main (int argc, char** argv) } /* get master tty just before chroot (lives in /dev) */ - ttyrec_getpty (); + if (!nhext && !nhauth) + ttyrec_getpty (); - /* chroot */ - if (chroot (myconfig->chroot)) + if (geteuid () != myconfig->shed_uid) { - perror ("cannot change root directory"); - graceful_exit (1); + /* chroot */ + if (chroot (myconfig->chroot)) + { + perror ("cannot change root directory"); + graceful_exit (1); + } + + if (chdir ("/")) + { + perror ("cannot chdir to root directory"); + graceful_exit (1); + } + + /* shed privs. this is done immediately after chroot. */ + if (setgroups (1, &myconfig->shed_gid) == -1) + { + perror ("setgroups"); + graceful_exit (1); + } + + if (setgid (myconfig->shed_gid) == -1) + { + perror ("setgid"); + graceful_exit (1); + } + + if (setuid (myconfig->shed_uid) == -1) + { + perror ("setuid"); + graceful_exit (1); + } } - if (chdir ("/")) + if (nhext) { - perror ("cannot chdir to root directory"); - graceful_exit (1); - } + char *myargv[3]; - /* shed privs. this is done immediately after chroot. */ - if (setgroups (1, &myconfig->shed_gid) == -1) - { - perror ("setgroups"); - graceful_exit (1); - } + myargv[0] = myconfig->game_path; + myargv[1] = "--proxy"; + myargv[2] = 0; - if (setgid (myconfig->shed_gid) == -1) - { - perror ("setgid"); - graceful_exit (1); - } - - if (setuid (myconfig->shed_uid) == -1) - { - perror ("setuid"); + execvp (myconfig->game_path, myargv); + perror (myconfig->game_path); graceful_exit (1); } @@ -1646,6 +1753,9 @@ main (int argc, char** argv) if (readfile (0)) graceful_exit (110); + if (nhauth) + graceful_exit (authenticate ()); + initcurses (); menuloop(); diff --git a/dgl-common.c b/dgl-common.c index d49c039..727ec1b 100644 --- a/dgl-common.c +++ b/dgl-common.c @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -43,7 +44,7 @@ char *chosen_name; struct dg_game ** populate_games (int *l) { - int fd, len, n; + int fd, len, n, is_nhext, pid; DIR *pdir; struct dirent *pdirent; struct stat pstat; @@ -72,22 +73,27 @@ populate_games (int *l) if (!strcmp (pdirent->d_name, ".") || !strcmp (pdirent->d_name, "..")) continue; + is_nhext = !strcmp (pdirent->d_name + strlen (pdirent->d_name) - 6, ".nhext"); + snprintf (fullname, 130, "%sinprogress/%s", myconfig->dglroot, 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_nhext || fcntl (fd, F_SETLK, &fl) == -1)) { /* stat to check idle status */ - snprintf (ttyrecname, 130, "%sttyrec/%s", myconfig->dglroot, pdirent->d_name); - replacestr = strchr (ttyrecname, ':'); - if (!replacestr) - graceful_exit (145); - replacestr[0] = '/'; - if (!stat (ttyrecname, &pstat)) + if (!is_nhext) + { + snprintf (ttyrecname, 130, "%sttyrec/%s", myconfig->dglroot, pdirent->d_name); + replacestr = strchr (ttyrecname, ':'); + if (!replacestr) + graceful_exit (145); + replacestr[0] = '/'; + } + if (is_nhext || !stat (ttyrecname, &pstat)) { /* now it's a valid game for sure */ games = realloc (games, sizeof (struct dg_game) * (len + 1)); @@ -119,6 +125,7 @@ populate_games (int *l) } else p = ""; + pid = atoi(p); while (*p != '\0' && *p != '\n') p++; if (*p != '\0') @@ -129,13 +136,30 @@ populate_games (int *l) if (*p != '\0') p++; games[len]->ws_col = atoi(p); - if (games[len]->ws_row < 4 || games[len]->ws_col < 4) + if (is_nhext) { - games[len]->ws_row = 24; - games[len]->ws_col = 80; - } - - len++; + if (kill (pid, 0) != 0) + { + /* Dead game */ + free (games[len]->ttyrec_fn); + free (games[len]->name); + free (games[len]->date); + free (games[len]->time); + free (games[len]); + unlink (fullname); + } + else + len++; + } + else + { + if (games[len]->ws_row < 4 || games[len]->ws_col < 4) + { + games[len]->ws_row = 24; + games[len]->ws_col = 80; + } + len++; + } } } else