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
This commit is contained in:
Jilles Tjoelker 2004-04-21 16:22:55 +00:00
parent 4d45d4d263
commit 545e5e8721
3 changed files with 204 additions and 46 deletions

View File

@ -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/<login>/*.ttyrec\ \ \ 'u
@ -122,7 +146,7 @@ dgldir/ttyrec/<login>/*.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.

View File

@ -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();

View File

@ -7,6 +7,7 @@
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
#include <pwd.h>
#include <grp.h>
@ -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