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 \-p
] ]
[
.B \-a
]
[
.B \-e
]
.ad .ad
.hy 14 .hy 14
.SH DESCRIPTION .SH DESCRIPTION
.PP .PP
.I dgamelaunch .I dgamelaunch
is a network-based game shell where anyone can sign up for an 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, account and start playing any game which suits your fancy - currently
it only supports NetHack. it supports NetHack and Slash'Em.
The user is presented with a curses-based menu to watch other games, edit the The user is presented with a curses-based menu to watch other games, edit the
options or play the game. 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. Don't print errors pertaining to the server configuration.
.TP .TP
.B .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 -p
Ignored; solely for compatibility with Ignored; solely for compatibility with
.B .B
@ -86,6 +108,8 @@ M. Drew Streib wrote the original version.
.PP .PP
Later, Joshua Kwan, Brett Carrington and Jilles Tjoelker added many new Later, Joshua Kwan, Brett Carrington and Jilles Tjoelker added many new
features. features.
.PP
NhExt support was written by J. Ali Harlow.
.SH FILES .SH FILES
.DT .DT
.ta \w'dgldir/ttyrec/<login>/*.ttyrec\ \ \ 'u .ta \w'dgldir/ttyrec/<login>/*.ttyrec\ \ \ 'u
@ -122,7 +146,7 @@ dgldir/ttyrec/<login>/*.ttyrec Recorded games, this may get
.\".SH ENVIRONMENT .\".SH ENVIRONMENT
.SH "SEE ALSO" .SH "SEE ALSO"
.PP .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 .SH BUGS
.PP .PP
None known. 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* char*
gen_inprogress_lock (pid_t pid, char* ttyrec_filename) gen_inprogress_lock (pid_t pid, char* ttyrec_filename)
{ {
@ -312,7 +330,8 @@ inprogressmenu ()
int i, menuchoice, len = 20, offset = 0, doresizewin = 0; int i, menuchoice, len = 20, offset = 0, doresizewin = 0;
time_t ctime; time_t ctime;
struct dg_game **games; struct dg_game **games;
char ttyrecname[130], *replacestr = NULL; char ttyrecname[130], *replacestr = NULL, gametype[10];
int is_nhext[14];
sigset_t oldmask, toblock; sigset_t oldmask, toblock;
games = populate_games (&len); games = populate_games (&len);
@ -343,9 +362,16 @@ inprogressmenu ()
if (i + offset >= len) if (i + offset >= len)
break; break;
mvprintw (7 + i, 1, "%c) %-15s (%3dx%3d) %s %s (%ldm %lds idle)", is_nhext[i] = !strcmp (games[i + offset]->ttyrec_fn + strlen (games[i + offset]->ttyrec_fn) - 6, ".nhext");
i + 97, games[i + offset]->name,
games[i + offset]->ws_col, games[i + offset]->ws_row, 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, games[i + offset]->date, games[i + offset]->time,
(time (&ctime) - games[i + offset]->idle_time) / 60, (time (&ctime) - games[i + offset]->idle_time) / 60,
(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 ((menuchoice - 'a') >= 0 && (menuchoice - 'a') < i)
{ {
if (is_nhext[menuchoice - 97]) /* Cannot watch NhExt game */
break;
/* valid choice has been made */ /* valid choice has been made */
snprintf (ttyrecname, 130, "%sttyrec/%s", myconfig->dglroot, snprintf (ttyrecname, 130, "%sttyrec/%s", myconfig->dglroot,
games[menuchoice - 97 + offset]->ttyrec_fn); 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 int
main (int argc, char** argv) main (int argc, char** argv)
{ {
@ -1568,14 +1651,21 @@ main (int argc, char** argv)
char atrcfilename[81], *spool; char atrcfilename[81], *spool;
unsigned int len; unsigned int len;
int c; 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) switch (c)
{ {
case 'q': case 'q':
silent = 1; break; silent = 1; break;
case 'a':
nhauth = 1; break;
case 'e':
nhext = 1; break;
case 'f': case 'f':
if (config) if (config)
{ {
@ -1608,37 +1698,54 @@ main (int argc, char** argv)
} }
/* get master tty just before chroot (lives in /dev) */ /* get master tty just before chroot (lives in /dev) */
ttyrec_getpty (); if (!nhext && !nhauth)
ttyrec_getpty ();
/* chroot */ if (geteuid () != myconfig->shed_uid)
if (chroot (myconfig->chroot))
{ {
perror ("cannot change root directory"); /* chroot */
graceful_exit (1); 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"); char *myargv[3];
graceful_exit (1);
}
/* shed privs. this is done immediately after chroot. */ myargv[0] = myconfig->game_path;
if (setgroups (1, &myconfig->shed_gid) == -1) myargv[1] = "--proxy";
{ myargv[2] = 0;
perror ("setgroups");
graceful_exit (1);
}
if (setgid (myconfig->shed_gid) == -1) execvp (myconfig->game_path, myargv);
{ perror (myconfig->game_path);
perror ("setgid");
graceful_exit (1);
}
if (setuid (myconfig->shed_uid) == -1)
{
perror ("setuid");
graceful_exit (1); graceful_exit (1);
} }
@ -1646,6 +1753,9 @@ main (int argc, char** argv)
if (readfile (0)) if (readfile (0))
graceful_exit (110); graceful_exit (110);
if (nhauth)
graceful_exit (authenticate ());
initcurses (); initcurses ();
menuloop(); menuloop();

View File

@ -7,6 +7,7 @@
#include <fcntl.h> #include <fcntl.h>
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <signal.h>
#include <unistd.h> #include <unistd.h>
#include <pwd.h> #include <pwd.h>
#include <grp.h> #include <grp.h>
@ -43,7 +44,7 @@ char *chosen_name;
struct dg_game ** struct dg_game **
populate_games (int *l) populate_games (int *l)
{ {
int fd, len, n; int fd, len, n, is_nhext, pid;
DIR *pdir; DIR *pdir;
struct dirent *pdirent; struct dirent *pdirent;
struct stat pstat; struct stat pstat;
@ -72,22 +73,27 @@ populate_games (int *l)
if (!strcmp (pdirent->d_name, ".") || !strcmp (pdirent->d_name, "..")) if (!strcmp (pdirent->d_name, ".") || !strcmp (pdirent->d_name, ".."))
continue; continue;
is_nhext = !strcmp (pdirent->d_name + strlen (pdirent->d_name) - 6, ".nhext");
snprintf (fullname, 130, "%sinprogress/%s", myconfig->dglroot, pdirent->d_name); snprintf (fullname, 130, "%sinprogress/%s", myconfig->dglroot, pdirent->d_name);
fd = 0; fd = 0;
/* O_RDWR here should be O_RDONLY, but we need to test for /* O_RDWR here should be O_RDONLY, but we need to test for
* an exclusive lock */ * an exclusive lock */
fd = open (fullname, O_RDWR); 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 */ /* stat to check idle status */
snprintf (ttyrecname, 130, "%sttyrec/%s", myconfig->dglroot, pdirent->d_name); if (!is_nhext)
replacestr = strchr (ttyrecname, ':'); {
if (!replacestr) snprintf (ttyrecname, 130, "%sttyrec/%s", myconfig->dglroot, pdirent->d_name);
graceful_exit (145); replacestr = strchr (ttyrecname, ':');
replacestr[0] = '/'; if (!replacestr)
if (!stat (ttyrecname, &pstat)) graceful_exit (145);
replacestr[0] = '/';
}
if (is_nhext || !stat (ttyrecname, &pstat))
{ {
/* now it's a valid game for sure */ /* now it's a valid game for sure */
games = realloc (games, sizeof (struct dg_game) * (len + 1)); games = realloc (games, sizeof (struct dg_game) * (len + 1));
@ -119,6 +125,7 @@ populate_games (int *l)
} }
else else
p = ""; p = "";
pid = atoi(p);
while (*p != '\0' && *p != '\n') while (*p != '\0' && *p != '\n')
p++; p++;
if (*p != '\0') if (*p != '\0')
@ -129,13 +136,30 @@ populate_games (int *l)
if (*p != '\0') if (*p != '\0')
p++; p++;
games[len]->ws_col = atoi(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; if (kill (pid, 0) != 0)
games[len]->ws_col = 80; {
} /* Dead game */
free (games[len]->ttyrec_fn);
len++; 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 else