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:
parent
4d45d4d263
commit
545e5e8721
|
@ -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.
|
||||
|
|
168
dgamelaunch.c
168
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();
|
||||
|
||||
|
|
52
dgl-common.c
52
dgl-common.c
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue