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 \-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.
|
||||||
|
|
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*
|
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();
|
||||||
|
|
||||||
|
|
52
dgl-common.c
52
dgl-common.c
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue