From 7ec2c4b9cc6c9e91cdd8daf7ae8b66af9131299d Mon Sep 17 00:00:00 2001 From: Pasi Kallinen Date: Thu, 29 Mar 2007 20:14:55 +0000 Subject: [PATCH] Allow more than one game per dgl installation. git-svn-id: svn://katsu.triplehelix.org/dgamelaunch/trunk@345 db0b04b0-f4d1-0310-9a6d-de3e77497b0e --- TODO | 6 + config.l | 5 + config.y | 166 ++++++++++++----- dgamelaunch.c | 374 +++++++++++++++++++++++++------------- dgamelaunch.h | 51 ++++-- dgl-common.c | 194 +++++++++++++++----- dgl-wall.c | 8 +- examples/dgamelaunch.conf | 74 ++++++-- ttyrec.c | 21 +-- ttyrec.h | 4 +- 10 files changed, 623 insertions(+), 280 deletions(-) diff --git a/TODO b/TODO index 25d9cd5..70069e6 100644 --- a/TODO +++ b/TODO @@ -1,3 +1,9 @@ +-configurable environment variables for when the game is launched +-configurable rcfilefmt and default rcfile name +-configurable stuff: max user name len, allowed chars in usernames, + allow mailing, allow char stripping, ... +-allow different banners for different games + - Flags for operators/staff/admins or (optionally) user-bans. - Localization of variables, code clean up diff --git a/config.l b/config.l index 3a73e85..4f6176f 100644 --- a/config.l +++ b/config.l @@ -57,6 +57,8 @@ COMMENT ^#.* "shed_gid" { return TYPE_SGID; } "maxusers" { return TYPE_MAX; } +"game_num" { return TYPE_GAMENUM; } + "chroot_path" { return TYPE_PATH_CHROOT; } "game_name" { return TYPE_NAME_GAME; } "game_path" { return TYPE_PATH_GAME; } @@ -67,6 +69,9 @@ COMMENT ^#.* "passwd" { return TYPE_PATH_PASSWD; } "lockfile" { return TYPE_PATH_LOCKFILE; } "savefilefmt" { return TYPE_PATH_SAVEFILEFMT; } +"inprogressdir" { return TYPE_PATH_INPROGRESS; } +"game_args" { return TYPE_GAME_ARGS; } +"rc_fmt" { return TYPE_RC_FMT; } \n { line++; col = 0; } diff --git a/config.y b/config.y index b38d82c..154baf4 100644 --- a/config.y +++ b/config.y @@ -17,6 +17,9 @@ extern void yyerror(const char*); extern char *yytext; extern unsigned int line, col; +extern int num_games; +int ncnf = 0; + static const char* lookup_token (int t); %} @@ -29,9 +32,9 @@ static const char* lookup_token (int t); %token TYPE_SUSER TYPE_SGROUP TYPE_SGID TYPE_SUID TYPE_MAX %token TYPE_PATH_GAME TYPE_NAME_GAME TYPE_PATH_DGLDIR TYPE_PATH_SPOOL -%token TYPE_PATH_BANNER TYPE_PATH_CANNED TYPE_PATH_CHROOT +%token TYPE_PATH_BANNER TYPE_PATH_CANNED TYPE_PATH_CHROOT TYPE_GAMENUM %token TYPE_PATH_PASSWD TYPE_PATH_LOCKFILE TYPE_PATH_SAVEFILEFMT -%token TYPE_MALSTRING +%token TYPE_MALSTRING TYPE_PATH_INPROGRESS TYPE_GAME_ARGS TYPE_RC_FMT %token TYPE_VALUE %token TYPE_NUMBER %type KeyType @@ -49,24 +52,34 @@ KeyPairs: KeyPairs KeyPair KeyPair: KeyType '=' TYPE_VALUE { struct group* gr; struct passwd* usr; - + + if (ncnf < 0 || ncnf >= DIFF_GAMES) { + fprintf(stderr, "%s:%d: illegal game number, bailing out\n", + config, line); + exit(1); + } + if (!myconfig) { - myconfig = calloc(1, sizeof(struct dg_config)); - myconfig->shed_uid = (uid_t)-1; - myconfig->shed_gid = (gid_t)-1; + int tmp; + myconfig = calloc(DIFF_GAMES, sizeof(myconfig[0])); + for (tmp = 0; tmp < DIFF_GAMES; tmp++) { + myconfig[tmp] = calloc(1, sizeof(struct dg_config)); + } + globalconfig.shed_uid = (uid_t)-1; + globalconfig.shed_gid = (gid_t)-1; } switch ($1) { case TYPE_SGROUP: - if (myconfig->shed_gid != (gid_t)-1) + if (globalconfig.shed_gid != (gid_t)-1) break; - - myconfig->shed_group = strdup($3); + + globalconfig.shed_group = strdup($3); if ((gr = getgrnam($3)) != NULL) { - myconfig->shed_gid = gr->gr_gid; + globalconfig.shed_gid = gr->gr_gid; if (!silent) fprintf(stderr, "%s:%d: suggest replacing 'shed_group = \"%s\"' line with 'shed_gid = %d'\n", config, line, $3, gr->gr_gid); @@ -76,23 +89,23 @@ KeyPair: KeyType '=' TYPE_VALUE { if (!silent) fprintf(stderr, "%s:%d: no such group '%s'\n", config, line, $3); } - + break; case TYPE_SUSER: - if (myconfig->shed_uid != (uid_t)-1) + if (globalconfig.shed_uid != (uid_t)-1) break; - + if (!strcmp($3, "root")) { fprintf(stderr, "%s:%d: I refuse to run as root! Aborting.\n", config, line); graceful_exit(1); } - myconfig->shed_user = strdup($3); + globalconfig.shed_user = strdup($3); if ((usr = getpwnam($3)) != NULL) { if (usr->pw_uid != 0) { - myconfig->shed_uid = usr->pw_uid; + globalconfig.shed_uid = usr->pw_uid; if (!silent) fprintf(stderr, "%s:%d: suggest replacing 'shed_user = \"%s\"' line with 'shed_uid = %d'\n", config, line, $3, usr->pw_uid); @@ -111,79 +124,118 @@ KeyPair: KeyType '=' TYPE_VALUE { break; case TYPE_PATH_CHROOT: - if (myconfig->chroot) free(myconfig->chroot); - myconfig->chroot = strdup ($3); + if (globalconfig.chroot) free(globalconfig.chroot); + globalconfig.chroot = strdup ($3); break; case TYPE_PATH_GAME: - if (myconfig->game_path) free(myconfig->game_path); - myconfig->game_path = strdup ($3); + if (myconfig[ncnf]->game_path) free(myconfig[ncnf]->game_path); + myconfig[ncnf]->game_path = strdup ($3); break; case TYPE_NAME_GAME: - if (myconfig->game_name) free (myconfig->game_name); - myconfig->game_name = strdup($3); + if (myconfig[ncnf]->game_name) free (myconfig[ncnf]->game_name); + myconfig[ncnf]->game_name = strdup($3); break; case TYPE_PATH_DGLDIR: - if (myconfig->dglroot) free(myconfig->dglroot); - myconfig->dglroot = strdup ($3); + if (globalconfig.dglroot) free(globalconfig.dglroot); + globalconfig.dglroot = strdup($3); break; case TYPE_PATH_BANNER: - if (myconfig->banner) free(myconfig->banner); - myconfig->banner = strdup($3); + if (globalconfig.banner) free(globalconfig.banner); + globalconfig.banner = strdup($3); break; case TYPE_PATH_CANNED: - if (myconfig->rcfile) free(myconfig->rcfile); - myconfig->rcfile = strdup($3); + if (myconfig[ncnf]->rcfile) free(myconfig[ncnf]->rcfile); + myconfig[ncnf]->rcfile = strdup($3); break; case TYPE_PATH_SPOOL: - if (myconfig->spool) free (myconfig->spool); - myconfig->spool = strdup($3); + if (myconfig[ncnf]->spool) free (myconfig[ncnf]->spool); + myconfig[ncnf]->spool = strdup($3); break; case TYPE_PATH_LOCKFILE: - if (myconfig->lockfile) free (myconfig->lockfile); - myconfig->lockfile = strdup($3); + if (myconfig[ncnf]->lockfile) free (myconfig[ncnf]->lockfile); + myconfig[ncnf]->lockfile = strdup($3); break; case TYPE_PATH_PASSWD: - if (myconfig->passwd) free(myconfig->passwd); - myconfig->passwd = strdup($3); + if (myconfig[ncnf]->passwd) free(myconfig[ncnf]->passwd); + myconfig[ncnf]->passwd = strdup($3); break; case TYPE_PATH_SAVEFILEFMT: - if (myconfig->savefilefmt) free(myconfig->savefilefmt); - myconfig->savefilefmt = strdup($3); + if (myconfig[ncnf]->savefilefmt) free(myconfig[ncnf]->savefilefmt); + myconfig[ncnf]->savefilefmt = strdup($3); + break; + + case TYPE_RC_FMT: + if (myconfig[ncnf]->rc_fmt) free(myconfig[ncnf]->rc_fmt); + myconfig[ncnf]->rc_fmt = strdup($3); + break; + + case TYPE_PATH_INPROGRESS: + if (myconfig[ncnf]->inprogressdir) free(myconfig[ncnf]->inprogressdir); + myconfig[ncnf]->inprogressdir = strdup($3); + break; + + case TYPE_GAME_ARGS: + { + char **tmpargs; + if (myconfig[ncnf]->bin_args) { + myconfig[ncnf]->num_args++; + tmpargs = calloc((myconfig[ncnf]->num_args+1), sizeof(char *)); + memcpy(tmpargs, myconfig[ncnf]->bin_args, (myconfig[ncnf]->num_args * sizeof(char *))); + free(myconfig[ncnf]->bin_args); + myconfig[ncnf]->bin_args = tmpargs; + } else { + myconfig[ncnf]->num_args = 1; + myconfig[ncnf]->bin_args = calloc(2, sizeof(char *)); + } + myconfig[ncnf]->bin_args[(myconfig[ncnf]->num_args)-1] = strdup($3); + myconfig[ncnf]->bin_args[(myconfig[ncnf]->num_args)] = 0; + } break; default: fprintf(stderr, "%s:%d: token %s does not take a string, bailing out\n", config, line, lookup_token($1)); exit(1); - + } free($3); } | KeyType '=' TYPE_MALSTRING {} | KeyType '=' TYPE_NUMBER { + + if (ncnf < 0 || ncnf >= DIFF_GAMES) { + fprintf(stderr, "%s:%d: illegal game number, bailing out\n", + config, line); + exit(1); + } + if (!myconfig) { - myconfig = calloc(1, sizeof(struct dg_config)); - myconfig->shed_uid = (uid_t)-1; - myconfig->shed_gid = (gid_t)-1; + int tmp; + myconfig = calloc(DIFF_GAMES, sizeof(myconfig[0])); + for (tmp = 0; tmp < DIFF_GAMES; tmp++) { + myconfig[tmp] = calloc(1, sizeof(struct dg_config)); + } + globalconfig.shed_uid = (uid_t)-1; + globalconfig.shed_gid = (gid_t)-1; } - + switch ($1) { case TYPE_SUID: - if (!silent && myconfig->shed_uid != (uid_t)-1 && myconfig->shed_uid != $3) + if (!silent && globalconfig.shed_uid != (uid_t)-1 && globalconfig.shed_uid != $3) fprintf(stderr, "%s:%d: 'shed_uid = %lu' entry overrides old setting %d\n", - config, line, $3, myconfig->shed_uid); + config, line, $3, globalconfig.shed_uid); /* Naive user protection - do not allow running as user root */ if ($3 == 0) @@ -192,20 +244,30 @@ KeyPair: KeyType '=' TYPE_VALUE { graceful_exit(1); } - myconfig->shed_uid = $3; + globalconfig.shed_uid = $3; break; case TYPE_SGID: - if (!silent && myconfig->shed_gid != (gid_t)-1 && myconfig->shed_gid != $3) + if (!silent && globalconfig.shed_gid != (gid_t)-1 && globalconfig.shed_gid != $3) fprintf(stderr, "%s:%d: 'shed_gid = %lu' entry overrides old setting %d\n", - config, line, $3, myconfig->shed_gid); + config, line, $3, globalconfig.shed_gid); - myconfig->shed_gid = $3; + globalconfig.shed_gid = $3; + break; + + case TYPE_GAMENUM: + if (($3 < 0) || ($3 >= DIFF_GAMES)) { + fprintf(stderr, "%s:%d: illegal game number, bailing out\n", + config, line); + exit(1); + } + ncnf = $3; + if (ncnf > num_games) + num_games = ncnf; break; case TYPE_MAX: - set_max = 1; /* XXX XXX */ - myconfig->max = $3; + globalconfig.max = $3; break; default: @@ -220,6 +282,7 @@ KeyType : TYPE_SUSER { $$ = TYPE_SUSER; } | TYPE_SUID { $$ = TYPE_SUID; } | TYPE_SGID { $$ = TYPE_SGID; } | TYPE_MAX { $$ = TYPE_MAX; } + | TYPE_GAMENUM { $$ = TYPE_GAMENUM; } | TYPE_PATH_CHROOT { $$ = TYPE_PATH_CHROOT; } | TYPE_PATH_GAME { $$ = TYPE_PATH_GAME; } | TYPE_NAME_GAME { $$ = TYPE_NAME_GAME; } @@ -230,6 +293,9 @@ KeyType : TYPE_SUSER { $$ = TYPE_SUSER; } | TYPE_PATH_PASSWD { $$ = TYPE_PATH_PASSWD; } | TYPE_PATH_LOCKFILE { $$ = TYPE_PATH_LOCKFILE; } | TYPE_PATH_SAVEFILEFMT { $$ = TYPE_PATH_SAVEFILEFMT; } + | TYPE_PATH_INPROGRESS { $$ = TYPE_PATH_INPROGRESS; } + | TYPE_GAME_ARGS { $$ = TYPE_GAME_ARGS; } + | TYPE_RC_FMT { $$ = TYPE_RC_FMT; } ; %% @@ -243,6 +309,7 @@ const char* lookup_token (int t) case TYPE_SUID: return "shed_uid"; case TYPE_SGID: return "shed_gid"; case TYPE_MAX: return "maxusers"; + case TYPE_GAMENUM: return "game_num"; case TYPE_PATH_CHROOT: return "chroot_path"; case TYPE_PATH_GAME: return "game_path"; case TYPE_NAME_GAME: return "game_name"; @@ -251,6 +318,9 @@ const char* lookup_token (int t) case TYPE_PATH_BANNER: return "banner"; case TYPE_PATH_CANNED: return "rc_template"; case TYPE_PATH_SAVEFILEFMT: return "savefilefmt"; + case TYPE_PATH_INPROGRESS: return "inprogressdir"; + case TYPE_GAME_ARGS: return "game_args"; + case TYPE_RC_FMT: return "rc_fmt"; default: abort(); } } diff --git a/dgamelaunch.c b/dgamelaunch.c index ab4bf36..19f23b9 100644 --- a/dgamelaunch.c +++ b/dgamelaunch.c @@ -89,7 +89,7 @@ extern int editor_main (int argc, char **argv); /* global variables */ char * __progname; -char rcfilename[80]; +/*char rcfilename[80];*/ int f_num = 0; struct dg_user **users = NULL; @@ -181,7 +181,7 @@ gen_nhext_filename () /* ************************************************************* */ char* -gen_inprogress_lock (pid_t pid, char* ttyrec_filename) +gen_inprogress_lock (int game, pid_t pid, char* ttyrec_filename) { char *lockfile = NULL, filebuf[80]; int fd; @@ -196,10 +196,10 @@ gen_inprogress_lock (pid_t pid, char* ttyrec_filename) fl.l_start = 0; fl.l_len = 0; - len = strlen(myconfig->dglroot) + strlen(me->username) + strlen(ttyrec_filename) + 13; + len = strlen(globalconfig.dglroot) + strlen(me->username) + strlen(ttyrec_filename) + 13; lockfile = calloc(len, sizeof(char)); - snprintf (lockfile, len, "%sinprogress/%s:%s", myconfig->dglroot, + snprintf (lockfile, len, "%s%s%s:%s", globalconfig.dglroot, myconfig[game]->inprogressdir, me->username, ttyrec_filename); fd = open (lockfile, O_WRONLY | O_CREAT, 0644); @@ -228,14 +228,14 @@ catch_sighup (int signum) /* ************************************************************* */ void -loadbanner (struct dg_banner *ban) +loadbanner (int game, struct dg_banner *ban) { FILE *bannerfile; char buf[80]; memset (buf, 0, 80); - bannerfile = fopen (myconfig->banner, "r"); + bannerfile = fopen (globalconfig.banner, "r"); if (!bannerfile) { @@ -245,9 +245,9 @@ loadbanner (struct dg_banner *ban) ban->lines[0] = strdup ("### dgamelaunch " PACKAGE_VERSION " - network console game launcher"); - len = strlen(myconfig->banner) + ARRAY_SIZE("### NOTE: administrator has not installed a file"); + len = strlen(globalconfig.banner) + ARRAY_SIZE("### NOTE: administrator has not installed a file"); ban->lines[1] = malloc(len); - snprintf(ban->lines[1], len, "### NOTE: administrator has not installed a %s file", myconfig->banner); + snprintf(ban->lines[1], len, "### NOTE: administrator has not installed a %s file", globalconfig.banner); return; } @@ -310,7 +310,7 @@ drawbanner (unsigned int start_line, unsigned int howmany) if (!loaded_banner) { - loadbanner (&banner); + loadbanner (0, &banner); loaded_banner = 1; } @@ -322,7 +322,7 @@ drawbanner (unsigned int start_line, unsigned int howmany) } void -inprogressmenu () +inprogressmenu (int gameid) { int i, menuchoice, len = 20, offset = 0, doresizewin = 0; time_t ctime; @@ -331,7 +331,7 @@ inprogressmenu () int is_nhext[14]; sigset_t oldmask, toblock; - games = populate_games (&len); + games = populate_games (gameid, &len); while (1) { @@ -416,7 +416,7 @@ inprogressmenu () break; /* valid choice has been made */ - snprintf (ttyrecname, 130, "%sttyrec/%s", myconfig->dglroot, + snprintf (ttyrecname, 130, "%sttyrec/%s", globalconfig.dglroot, games[menuchoice - 97 + offset]->ttyrec_fn); chosen_name = strdup (games[menuchoice - 97 + offset]->name); @@ -452,7 +452,7 @@ inprogressmenu () } } - games = populate_games (&len); + games = populate_games (gameid, &len); } } @@ -623,6 +623,7 @@ domailuser (char *username) FILE *user_spool = NULL; time_t now; int mail_empty = 1; + int game; struct flock fl = { 0 }; fl.l_type = F_WRLCK; @@ -632,10 +633,14 @@ domailuser (char *username) assert (loggedin); - len = strlen(myconfig->spool) + strlen (username) + 1; + game = 0; /*TODO: find_curr_player_game(username) */ + + if (strlen(myconfig[game]->spool) < 1) return; + + len = strlen(myconfig[game]->spool) + strlen (username) + 1; spool_fn = malloc (len + 1); time (&now); - snprintf (spool_fn, len + 1, "%s/%s", myconfig->spool, username); + snprintf (spool_fn, len + 1, "%s/%s", myconfig[game]->spool, username); /* print the enter your message line */ clear (); @@ -703,10 +708,46 @@ domailuser (char *username) return; } +void +drawgamemenu(int game) +{ + static int flood = 0; + + if (loggedin) { + + clear(); + + drawbanner(1,0); + + mvprintw(banner.len + 2, 1, "Logged in as: %s", me->username); + + mvaddstr (banner.len + 4, 1, "c) Change password"); + mvaddstr (banner.len + 5, 1, "e) Change email address"); + mvaddstr (banner.len + 6, 1, "w) Watch games in progress"); + if (myconfig[game]->rcfile) + mvprintw (banner.len + 7, 1, "o) Edit options for %s", myconfig[game]->game_name); + mvprintw (banner.len + 8, 1, "p) Play %s", myconfig[game]->game_name); + mvaddstr (banner.len + 9, 1, "q) Return to previous menu"); + mvaddstr (banner.len + 11, 1, "=> "); + + refresh (); + } + + /* for retarded clients */ + flood++; + if (flood >= 20) + { + endwin(); + graceful_exit (119); + } + +} + void drawmenu () { static int flood = 0; + int game = 0; clear (); @@ -717,11 +758,17 @@ drawmenu () mvprintw (banner.len + 2, 1, "Logged in as: %s", me->username); mvaddstr (banner.len + 4, 1, "c) Change password"); mvaddstr (banner.len + 5, 1, "e) Change email address"); - mvaddstr (banner.len + 6, 1, "o) Edit option file"); - mvaddstr (banner.len + 7, 1, "w) Watch games in progress"); - mvprintw (banner.len + 8, 1, "p) Play %s!", myconfig->game_name); - mvaddstr (banner.len + 9, 1, "q) Quit"); - mvaddstr (banner.len + 11, 1, "=> "); + mvaddstr (banner.len + 6, 1, "w) Watch games in progress"); + if (num_games >= 1) + for (game = 0; (game <= num_games) && myconfig && myconfig[game] && myconfig[game]->game_name; game++) + mvprintw (banner.len + 7 + game, 1, "%c) Go to %s menu", '1'+game, myconfig[game]->game_name); + else { + if (myconfig[0]->rcfile) + mvprintw (banner.len + 7, 1, "o) Edit options"); + mvprintw (banner.len + 8, 1, "p) Play %s", myconfig[0]->game_name); + } + mvaddstr (banner.len + 9 + game, 1, "q) Quit"); + mvaddstr (banner.len + 11 + game, 1, "=> "); } else { @@ -730,7 +777,7 @@ drawmenu () mvaddstr (banner.len + 5, 1, "r) Register new user"); mvaddstr (banner.len + 6, 1, "w) Watch games in progress"); mvaddstr (banner.len + 7, 1, "q) Quit"); - mvaddstr (banner.len + 9, 1, "=> "); + mvaddstr (banner.len + 11, 1, "=> "); } refresh (); @@ -796,7 +843,6 @@ autologin (char* user, char *pass) if (passwordgood(pass)) { loggedin = 1; - snprintf (rcfilename, 80, "%srcfiles/%s.nethackrc", myconfig->dglroot, me->username); setproctitle ("%s", me->username); } } @@ -859,7 +905,6 @@ loginprompt (int from_ttyplay) if (passwordgood (pw_buf)) { loggedin = 1; - snprintf (rcfilename, 80, "%srcfiles/%s.nethackrc", myconfig->dglroot, me->username); setproctitle ("%s", me->username); } else @@ -885,7 +930,7 @@ newuser () loggedin = 0; - if (f_num >= myconfig->max) + if (f_num >= globalconfig.max) { clear (); @@ -1008,14 +1053,10 @@ newuser () loggedin = 1; - snprintf (rcfilename, 80, "%srcfiles/%s.nethackrc", myconfig->dglroot, me->username); setproctitle ("%s", me->username); - if (access (rcfilename, R_OK) == -1) - write_canned_rcfile (rcfilename); - /* create their ttyrec dir */ - snprintf (dirname, 100, "%sttyrec/%s", myconfig->dglroot, me->username); + snprintf (dirname, 100, "%sttyrec/%s", globalconfig.dglroot, me->username); if (access (dirname, F_OK) != 0) mkdir (dirname, 0755); @@ -1057,14 +1098,14 @@ readfile (int nolock) if (!nolock) { - fpl = fopen (myconfig->lockfile, "r"); + fpl = fopen (myconfig[0]->lockfile, "r"); if (!fpl) graceful_exit (106); if (fcntl (fileno (fpl), F_SETLKW, &fl) == -1) graceful_exit (114); } - fp = fopen (myconfig->passwd, "r"); + fp = fopen (myconfig[0]->passwd, "r"); if (!fp) graceful_exit (106); @@ -1132,7 +1173,7 @@ readfile (int nolock) f_num++; /* prevent a buffer overrun here */ - if (f_num > myconfig->max) + if (f_num > globalconfig.max) { fprintf(stderr,"ERROR: number of users in database exceeds maximum. Exiting.\n"); graceful_exit (109); @@ -1164,15 +1205,15 @@ userexist (char *cname) /* ************************************************************* */ void -write_canned_rcfile (char *target) +write_canned_rcfile (int game, char *target) { FILE *canned, *newfile; char buf[1024], *rfn; size_t bytes, len; - len = strlen(myconfig->rcfile) + 2; + len = strlen(myconfig[game]->rcfile) + 2; rfn = malloc(len); - snprintf (rfn, len, "/%s", myconfig->rcfile); + snprintf (rfn, len, "/%s", myconfig[game]->rcfile); if (!(newfile = fopen (target, "w"))) { @@ -1180,7 +1221,7 @@ write_canned_rcfile (char *target) mvaddstr (13, 1, "You don't know how to write that! You write \"%s was here\" and the scroll disappears."); mvaddstr (14, 1, - "(Sorry, but I couldn't open one of the nethackrc files. This is a bug.)"); + "(Sorry, but I couldn't open one of the config files. This is a bug.)"); return; } @@ -1211,20 +1252,20 @@ write_canned_rcfile (char *target) void -editoptions () +editoptions (int game) { FILE *rcfile; char *myargv[3]; pid_t editor; - rcfile = fopen (rcfilename, "r"); - if (!rcfile) /* should not really happen except for old users */ - write_canned_rcfile (rcfilename); + rcfile = fopen (dgl_format_str(game, me, myconfig[game]->rc_fmt), "r"); + if (!rcfile) + write_canned_rcfile (game, dgl_format_str(game, me, myconfig[game]->rc_fmt)); /* use whatever editor_main to edit */ myargv[0] = ""; - myargv[1] = rcfilename; + myargv[1] = dgl_format_str(game, me, myconfig[game]->rc_fmt); myargv[2] = 0; endwin (); @@ -1270,7 +1311,7 @@ writefile (int requirenew) sigaddset(&toblock, SIGTERM); sigprocmask(SIG_BLOCK, &toblock, &oldmask); - fpl = fopen (myconfig->lockfile, "r+"); + fpl = fopen (myconfig[0]->lockfile, "r+"); if (!fpl) { sigprocmask(SIG_SETMASK, &oldmask, NULL); @@ -1287,7 +1328,7 @@ writefile (int requirenew) freefile (); readfile (1); - fp = fopen (myconfig->passwd, "w"); + fp = fopen (myconfig[0]->passwd, "w"); if (!fp) { sigprocmask(SIG_SETMASK, &oldmask, NULL); @@ -1319,7 +1360,7 @@ writefile (int requirenew) } if (loggedin && !my_done) { /* new entry */ - if (f_num < myconfig->max) + if (f_num < globalconfig.max) fprintf (fp, "%s:%s:%s:%s\n", me->username, me->email, me->password, me->env); else /* Oops, someone else registered the last available slot first */ @@ -1345,65 +1386,30 @@ writefile (int requirenew) /* ************************************************************* */ /* ************************************************************* */ + /* * Backup the savefile, if configured. * Returns non-zero if successful, otherwise an error message has been * given already. */ int -backup_savefile (void) +backup_savefile (int game) { - char buf[1024]; - char *f, *p, *end; + /*char buf[1024];*/ + char *f, *p, *end, *buf; int ispercent = 0, n; int in, out; - f = myconfig->savefilefmt; + f = myconfig[game]->savefilefmt; if (*f == '\0') return 1; if (me == NULL) graceful_exit (147); + buf = dgl_format_str(game, me, f); p = buf; - end = buf + sizeof(buf) - 10; /* make sure we can add .bak */ - while (*f) - { - if (ispercent) - { - switch (*f) - { - case 'u': - snprintf (p, end + 1 - p, "%d", myconfig->shed_uid); - while (*p != '\0') - p++; - break; - case 'n': - snprintf (p, end + 1 - p, "%s", me->username); - while (*p != '\0') - p++; - break; - default: - *p = *f; - if (p < end) - p++; - } - ispercent = 0; - } - else - { - if (*f == '%') - ispercent = 1; - else - { - *p = *f; - if (p < end) - p++; - } - } - f++; - } - *p = '\0'; + p += strlen(buf); /*fprintf(stderr, "***\n[SAVEFILE=%s]\n***\n", buf); sleep(3);*/ @@ -1443,7 +1449,7 @@ backup_savefile (void) } int -purge_stale_locks (void) +purge_stale_locks (int game) { DIR *pdir; struct dirent *dent; @@ -1451,10 +1457,10 @@ purge_stale_locks (void) size_t len; short firsttime = 1; - len = strlen(myconfig->dglroot) + ARRAY_SIZE("inprogress/") + 1; + len = strlen(globalconfig.dglroot) + strlen(myconfig[game]->inprogressdir) + 1; dir = malloc(len); - snprintf(dir, len, "%sinprogress/", myconfig->dglroot); - + snprintf(dir, len, "%s%s", globalconfig.dglroot, myconfig[game]->inprogressdir); + if (!(pdir = opendir (dir))) graceful_exit (200); @@ -1468,7 +1474,7 @@ purge_stale_locks (void) pid_t pid; size_t len; int seconds = 0; - + if (!strcmp (dent->d_name, ".") || !strcmp (dent->d_name, "..")) continue; @@ -1482,10 +1488,12 @@ purge_stale_locks (void) if (strncmp (dent->d_name, me->username, colon - dent->d_name)) continue; - len = strlen (dent->d_name) + strlen(myconfig->dglroot) + 12; + len = strlen (dent->d_name) + strlen(globalconfig.dglroot) + 12; fn = malloc (len); - snprintf (fn, len, "%sinprogress/%s", myconfig->dglroot, dent->d_name); + snprintf (fn, len, "%s%s%s", globalconfig.dglroot, myconfig[game]->inprogressdir, dent->d_name); + + fprintf (stderr, "ERR:'%s'\n", fn); if (!(ipfile = fopen (fn, "r"))) graceful_exit (202); @@ -1503,13 +1511,13 @@ purge_stale_locks (void) #define HUP_WAIT 10 /* seconds before HUPPING */ mvprintw (3, 1, "There are some stale %s processes, will recover in %d seconds.", - myconfig->game_name, HUP_WAIT); + myconfig[game]->game_name, HUP_WAIT); mvaddstr (4, 1, "Press a key NOW if you don't want this to happen!"); - move (3, 58); /* pedantry */ + move (3, 51 + strlen(myconfig[game]->game_name)); /* pedantry */ halfdelay(10); - + for (seconds = HUP_WAIT - 1; seconds >= 0; seconds--) { if (getch() != ERR) @@ -1518,12 +1526,12 @@ purge_stale_locks (void) cbreak(); return 0; } - mvprintw (3, 57, "%d%s", seconds, (seconds > 9) ? "" : " "); + mvprintw (3, 50 + strlen(myconfig[game]->game_name), "%d%s", seconds, (seconds > 9) ? "" : " "); } nocbreak(); cbreak(); - + firsttime = 0; } @@ -1545,7 +1553,7 @@ purge_stale_locks (void) if (seconds == 10) { mvprintw (3, 1, - "Couldn't terminate one of your stale %s processes gracefully.", myconfig->game_name); + "Couldn't terminate one of your stale %s processes gracefully.", myconfig[game]->game_name); mvaddstr (4, 1, "Force its termination? [yn] "); if (tolower (getch ()) == 'y') { @@ -1556,7 +1564,7 @@ purge_stale_locks (void) { endwin (); fprintf (stderr, "Sorry, no %s for you now, please " - "contact the admin.\n", myconfig->game_name); + "contact the admin.\n", myconfig[game]->game_name); graceful_exit (1); } } @@ -1571,16 +1579,22 @@ purge_stale_locks (void) return 1; } -void -menuloop (void) +int +gamemenuloop(int game) { int userchoice = 0; - while ((userchoice != 'p') | (!loggedin)) + while (1) { - drawmenu (); + drawgamemenu (game); userchoice = getch (); switch (tolower (userchoice)) { + default: + break; + case 'p': + if (loggedin) + return 1; + break; case 'c': if (loggedin) changepw (1); @@ -1590,15 +1604,16 @@ menuloop (void) change_email(); break; case 'w': - inprogressmenu (); - break; - case 'o': - if (loggedin) - editoptions (); + inprogressmenu (game); break; + case 'o': + if (loggedin && myconfig[game]->rcfile) + editoptions (game); + break; case 'q': - endwin (); - graceful_exit(0); + return 0; + /* endwin (); + graceful_exit(0);*/ /* break; */ case 'r': if (!loggedin) /*not visible to loggedin */ @@ -1607,11 +1622,67 @@ menuloop (void) case 'l': if (!loggedin) /* not visible to loggedin */ loginprompt (0); - break; } } + return 0; } +int +menuloop (void) +{ + int userchoice = 0; + while (1) + { + drawmenu (); + userchoice = getch (); + + if ((num_games >= 1) && loggedin && (userchoice >= '1') && (userchoice <= ('1'+num_games))) { + int game = userchoice - '1'; + if (myconfig[game] && myconfig[game]->game_name) { + if (gamemenuloop(game)) return game; + } + } else { + switch (tolower (userchoice)) + { + default: + break; + case 'c': + if (loggedin) + changepw (1); + break; + case 'e': + if (loggedin) + change_email(); + break; + case 'w': + inprogressmenu (-1); + break; + case 'o': + if (loggedin && (num_games == 0) && myconfig[0]->rcfile) + editoptions(0); + break; + case 'p': + if (loggedin && (num_games == 0)) + return 0; + break; + case 'q': + endwin (); + graceful_exit(0); + /* break; */ + case 'r': + if (!loggedin) /*not visible to loggedin */ + newuser (); + break; + case 'l': + if (!loggedin) /* not visible to loggedin */ + loginprompt (0); + } + } + } + return -1; +} + + int authenticate () { @@ -1648,7 +1719,7 @@ authenticate () me = users[me_index]; if (passwordgood (pw_buf)) { - games = populate_games (&len); + games = populate_games (-1, &len); for (i = 0; i < len; i++) if (!strcmp (games[i]->name, user_buf)) { @@ -1656,7 +1727,7 @@ authenticate () return 1; } win.ws_row = win.ws_col = 0; - gen_inprogress_lock (getppid (), gen_nhext_filename ()); + gen_inprogress_lock (0, getppid (), gen_nhext_filename ()); return 0; } } @@ -1674,6 +1745,7 @@ main (int argc, char** argv) unsigned int len; int c; int nhext = 0, nhauth = 0; + int userchoice; #ifndef HAVE_SETPROCTITLE /* save argc, argv */ @@ -1754,10 +1826,10 @@ main (int argc, char** argv) if (!nhext && !nhauth) ttyrec_getpty (); - if (geteuid () != myconfig->shed_uid) + if (geteuid () != globalconfig.shed_uid) { /* chroot */ - if (chroot (myconfig->chroot)) + if (chroot (globalconfig.chroot)) { perror ("cannot change root directory"); graceful_exit (1); @@ -1770,19 +1842,19 @@ main (int argc, char** argv) } /* shed privs. this is done immediately after chroot. */ - if (setgroups (1, &myconfig->shed_gid) == -1) + if (setgroups (1, &globalconfig.shed_gid) == -1) { perror ("setgroups"); graceful_exit (1); } - if (setgid (myconfig->shed_gid) == -1) + if (setgid (globalconfig.shed_gid) == -1) { perror ("setgid"); graceful_exit (1); } - if (setuid (myconfig->shed_uid) == -1) + if (setuid (globalconfig.shed_uid) == -1) { perror ("setuid"); graceful_exit (1); @@ -1793,12 +1865,12 @@ main (int argc, char** argv) { char *myargv[3]; - myargv[0] = myconfig->game_path; + myargv[0] = myconfig[0]->game_path; myargv[1] = "--proxy"; myargv[2] = 0; - execvp (myconfig->game_path, myargv); - perror (myconfig->game_path); + execvp (myconfig[0]->game_path, myargv); + perror (myconfig[0]->game_path); graceful_exit (1); } @@ -1829,29 +1901,44 @@ main (int argc, char** argv) } initcurses (); - menuloop(); + + userchoice = menuloop(); assert (loggedin); - while (!purge_stale_locks()) - menuloop(); + if ((userchoice >= 0) && (userchoice <= num_games)) { + while (!purge_stale_locks(userchoice)) { + userchoice = gamemenuloop(userchoice); + } + if (!((userchoice >= 0) && (userchoice <= num_games))) + graceful_exit (1); + } else { + graceful_exit (1); + } + + if (myconfig[userchoice]->rcfile) { + if (access (dgl_format_str(userchoice, me, myconfig[userchoice]->rc_fmt), R_OK) == -1) + write_canned_rcfile (userchoice, dgl_format_str(userchoice, me, myconfig[userchoice]->rc_fmt)); + } setproctitle ("%s [playing]", me->username); endwin (); signal(SIGWINCH, SIG_DFL); - if (!backup_savefile ()) + if (!backup_savefile (userchoice)) graceful_exit (5); /* environment */ - snprintf (atrcfilename, 81, "@%s", rcfilename); + if (myconfig[userchoice]->rcfile) { + snprintf (atrcfilename, 81, "@%s", dgl_format_str(userchoice, me, myconfig[userchoice]->rc_fmt)); + mysetenv ("NETHACKOPTIONS", atrcfilename, 1); + } - len = strlen(myconfig->spool) + strlen (me->username) + 1; + len = strlen(myconfig[userchoice]->spool) + strlen (me->username) + 1; spool = malloc (len + 1); - snprintf (spool, len + 1, "%s/%s", myconfig->spool, me->username); + snprintf (spool, len + 1, "%s/%s", myconfig[userchoice]->spool, me->username); - mysetenv ("NETHACKOPTIONS", atrcfilename, 1); mysetenv ("MAIL", spool, 1); mysetenv ("SIMPLEMAIL", "1", 1); @@ -1861,15 +1948,40 @@ main (int argc, char** argv) free (spool); + /* fix the variables in the arguments */ + for (i = 0; i < myconfig[userchoice]->num_args; i++) { + char *tmp = strdup(dgl_format_str(userchoice, me, myconfig[userchoice]->bin_args[i])); + free(myconfig[userchoice]->bin_args[i]); + myconfig[userchoice]->bin_args[i] = tmp; + } + /* launch program */ - ttyrec_main (me->username, gen_ttyrec_filename()); + ttyrec_main (userchoice, me->username, gen_ttyrec_filename()); /* NOW we can safely kill this */ freefile (); + /* + printf("config:'%s'\n", config); + + printf("chroot:'%s'\n", globalconfig.chroot); + printf("gamepath:'%s'\n", myconfig[userchoice]->game_path); + printf("game:'%s'\n", myconfig[userchoice]->game_name); + printf("dglroot:'%s'\n", globalconfig.dglroot); + printf("lockfile:'%s'\n", myconfig[userchoice]->lockfile); + printf("passwd:'%s'\n", myconfig[userchoice]->passwd); + printf("banner:'%s'\n", globalconfig.banner); + printf("rcfile:'%s'\n", myconfig[userchoice]->rcfile); + printf("spool:'%s'\n", myconfig[userchoice]->spool); + printf("savefilefmt:'%s'\n", myconfig[userchoice]->savefilefmt); + printf("dgl_format_str(savefilefmt):'%s'\n", dgl_format_str(userchoice, myconfig[userchoice]->savefilefmt)); + printf("inprogressdir:'%s'\n", myconfig[userchoice]->inprogressdir); + */ + if (me) free (me); graceful_exit (1); + return 1; } diff --git a/dgamelaunch.h b/dgamelaunch.h index 692cbe8..7eb7b31 100644 --- a/dgamelaunch.h +++ b/dgamelaunch.h @@ -12,6 +12,10 @@ # define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) #endif + +/* max # of different games playable from within this dgl */ +#define DIFF_GAMES 3 + struct dg_user { char *username; @@ -39,41 +43,54 @@ struct dg_game struct dg_config { - char* chroot; char* game_path; char* game_name; - char* dglroot; char* lockfile; char* passwd; - char* banner; char* rcfile; char* spool; - char* shed_user; - char* shed_group; - uid_t shed_uid; - gid_t shed_gid; - unsigned long max; char* savefilefmt; + char* inprogressdir; + int num_args; /* # of bin_args */ + char **bin_args; /* args for game binary */ + char *rc_fmt; +}; + +struct dg_globalconfig +{ + char* chroot; + char* dglroot; + char* banner; + unsigned long max; + char* shed_user; + char* shed_group; + uid_t shed_uid; + gid_t shed_gid; }; /* Global variables */ extern char* config; /* file path */ -extern struct dg_config *myconfig; +extern struct dg_config **myconfig; extern char *chosen_name; extern int loggedin; extern int silent; extern int set_max; +extern struct dg_globalconfig globalconfig; + +extern int num_games; + /* dgamelaunch.c */ extern void create_config(void); extern void ttyrec_getmaster(void); extern char *gen_ttyrec_filename(void); -extern char *gen_inprogress_lock(pid_t pid, char *ttyrec_filename); +extern char *gen_inprogress_lock(int game, pid_t pid, char *ttyrec_filename); extern void catch_sighup(int signum); -extern void loadbanner(struct dg_banner *ban); +extern void loadbanner(int game, struct dg_banner *ban); extern void drawbanner(unsigned int start_line, unsigned int howmany); -extern struct dg_game **populate_games(int *l); -extern void inprogressmenu(void); +extern char *dgl_format_str(int game, struct dg_user *me, char *str); +extern struct dg_game **populate_games(int game, int *l); +extern void inprogressmenu(int gameid); extern void change_email(void); extern int changepw(int dowrite); extern void domailuser(char *username); @@ -86,12 +103,12 @@ extern void autologin(char *user, char *pass); extern int passwordgood(char *cpw); extern int readfile(int nolock); extern int userexist(char *cname); -extern void write_canned_rcfile(char *target); -extern void editoptions(void); +extern void write_canned_rcfile(int game, char *target); +extern void editoptions(int game); extern void writefile(int requirenew); extern void graceful_exit(int status); -extern int purge_stale_locks(void); -extern void menuloop(void); +extern int purge_stale_locks(int game); +extern int menuloop(void); extern void ttyrec_getpty(void); #if !defined(BSD) && !defined(__linux__) extern int mysetenv (const char* name, const char* value, int overwrite); diff --git a/dgl-common.c b/dgl-common.c index 4645663..870ec11 100644 --- a/dgl-common.c +++ b/dgl-common.c @@ -16,33 +16,100 @@ extern FILE* yyin; extern int yyparse (); /* Data structures */ -struct dg_config *myconfig = NULL; +struct dg_config **myconfig = NULL; struct dg_config defconfig = { - /* chroot = */ "/var/lib/dgamelaunch/", + /* chroot = */ /*"/var/lib/dgamelaunch/",*/ /* game_path = */ "/bin/nethack", /* game_name = */ "NetHack", - /* dglroot = */ "/dgldir/", + /* dglroot = *//* "/dgldir/",*/ /* lockfile = */ "/dgl-lock", /* passwd = */ "/dgl-login", - /* banner = */ "/dgl-banner", - /* rcfile = */ "/dgl-default-rcfile", + /* banner = */ /*"/dgl-banner",*/ + /* rcfile = */ NULL, /*"/dgl-default-rcfile",*/ /* spool = */ "/var/mail/", - /* shed_user = */ "games", - /* shed_group = */ "games", - /* shed_uid = */ 5, - /* shed_gid = */ 60, /* games:games in Debian */ - /* max = */ 64000, - /* savefilefmt = */ "" /* don't do this by default */ + /* shed_user = */ /*"games",*/ + /* shed_group = */ /*"games",*/ + /* shed_uid = *//* 5,*/ + /* shed_gid = */ /*60,*/ /* games:games in Debian */ + /* max = */ /*64000,*/ + /* savefilefmt = */ "", /* don't do this by default */ + /* inprogressdir = */ "inprogress/", + /* num_args = */ 0, + /* bin_args = */ NULL, + /* rc_fmt = */ "%rrcfiles/%n.nethackrc" /* [dglroot]rcfiles/[username].nethackrc */ }; char* config = NULL; int silent = 0; -int set_max = 0; /* XXX */ +/*int set_max = 0;*/ /* XXX */ int loggedin = 0; char *chosen_name; +int num_games = 0; + +struct dg_globalconfig globalconfig; + +/* + * replace following codes with variables: + * %u == shed_uid (number) + * %n == user name (string) + * %r == chroot (string) + */ +char * +dgl_format_str(int game, struct dg_user *me, char *str) +{ + static char buf[1024]; + char *f, *p, *end; + int ispercent = 0; + + if (!str) return NULL; + + f = str; + p = buf; + end = buf + sizeof(buf) - 10; + + while (*f) { + if (ispercent) { + switch (*f) { + case 'u': + snprintf (p, end + 1 - p, "%d", globalconfig.shed_uid); + while (*p != '\0') + p++; + break; + case 'n': + snprintf (p, end + 1 - p, "%s", me->username); + while (*p != '\0') + p++; + break; + case 'r': + snprintf (p, end + 1 - p, "%s", globalconfig.dglroot); + while (*p != '\0') + p++; + break; + default: + *p = *f; + if (p < end) + p++; + } + ispercent = 0; + } else { + if (*f == '%') + ispercent = 1; + else { + *p = *f; + if (p < end) + p++; + } + } + f++; + } + *p = '\0'; + + return buf; +} + struct dg_game ** -populate_games (int *l) +populate_games (int xgame, int *l) { int fd, len, n, is_nhext, pid; DIR *pdir; @@ -54,28 +121,32 @@ populate_games (int *l) struct flock fl = { 0 }; size_t slen; + int game; + fl.l_type = F_WRLCK; fl.l_whence = SEEK_SET; fl.l_start = 0; fl.l_len = 0; len = 0; - - slen = strlen(myconfig->dglroot) + ARRAY_SIZE("inprogress/") + 1; - dir = malloc(slen); - snprintf(dir, slen, "%sinprogress/", myconfig->dglroot); - if (!(pdir = opendir (dir))) + for (game = ((xgame < 0) ? 0 : xgame); game <= ((xgame < 0) ? num_games : xgame); game++) { + + slen = strlen(globalconfig.dglroot) + strlen(myconfig[game]->inprogressdir) + 1; + dir = malloc(slen); + snprintf(dir, slen, "%s%s", globalconfig.dglroot, myconfig[game]->inprogressdir); + + if (!(pdir = opendir (dir))) graceful_exit (140); - while ((pdirent = readdir (pdir))) + while ((pdirent = readdir (pdir))) { 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); + snprintf (fullname, 130, "%s%s%s", globalconfig.dglroot, myconfig[game]->inprogressdir, pdirent->d_name); fd = 0; /* O_RDWR here should be O_RDONLY, but we need to test for @@ -87,7 +158,7 @@ populate_games (int *l) /* stat to check idle status */ if (!is_nhext) { - snprintf (ttyrecname, 130, "%sttyrec/%s", myconfig->dglroot, pdirent->d_name); + snprintf (ttyrecname, 130, "%sttyrec/%s", globalconfig.dglroot, pdirent->d_name); replacestr = strchr (ttyrecname, ':'); if (!replacestr) graceful_exit (145); @@ -172,7 +243,8 @@ populate_games (int *l) fl.l_type = F_WRLCK; } - closedir (pdir); + closedir (pdir); + } *l = len; return games; } @@ -197,6 +269,7 @@ void create_config () { FILE *config_file = NULL; + int tmp; if (config) { @@ -217,52 +290,73 @@ create_config () else { #ifdef DEFCONFIG + /* fprintf(stderr, "DEFCONFIG: %s\n", DEFCONFIG);*/ config = DEFCONFIG; if ((config_file = fopen(DEFCONFIG, "r")) != NULL) { yyin = config_file; + /* fprintf(stderr, "PARSING\n");*/ yyparse(); + /* fprintf(stderr, "PARSED\n");*/ fclose(config_file); } #else - myconfig = &defconfig; + /* fprintf(stderr, "NO DEFCONFIG\n");*/ + myconfig = calloc(DIFF_GAMES, sizeof(myconfig[0])); + for (tmp = 0; tmp < DIFF_GAMES; tmp++) + myconfig[tmp] = NULL; + myconfig[0] = &defconfig; return; #endif } if (!myconfig) /* a parse error occurred */ { - myconfig = &defconfig; + /* fprintf(stderr, "PARSE ERROR\n");*/ + myconfig = calloc(DIFF_GAMES, sizeof(myconfig[0])); + for (tmp = 0; tmp < DIFF_GAMES; tmp++) + myconfig[tmp] = NULL; + myconfig[0] = &defconfig; return; } /* Fill the rest with defaults */ - if (!myconfig->shed_user && myconfig->shed_uid == (uid_t)-1) - { - struct passwd *pw; - if ((pw = getpwnam(defconfig.shed_user))) - myconfig->shed_uid = pw->pw_uid; - else - myconfig->shed_uid = defconfig.shed_uid; - } - if (!myconfig->shed_group && myconfig->shed_gid == (gid_t)-1) - { - struct group *gr; - if ((gr = getgrnam(defconfig.shed_group))) - myconfig->shed_gid = gr->gr_gid; - else - myconfig->shed_gid = defconfig.shed_gid; + for (tmp = 0; tmp < DIFF_GAMES; tmp++) { + + if (!myconfig[tmp]->game_path) myconfig[tmp]->game_path = defconfig.game_path; + if (!myconfig[tmp]->game_name) myconfig[tmp]->game_name = defconfig.game_name; + if (!myconfig[tmp]->rcfile) myconfig[tmp]->rcfile = defconfig.rcfile; + if (!myconfig[tmp]->spool) myconfig[tmp]->spool = defconfig.spool; + if (!myconfig[tmp]->passwd) myconfig[tmp]->passwd = defconfig.passwd; + if (!myconfig[tmp]->lockfile) myconfig[tmp]->lockfile = defconfig.lockfile; + if (!myconfig[tmp]->savefilefmt) myconfig[tmp]->savefilefmt = defconfig.savefilefmt; + if (!myconfig[tmp]->inprogressdir) myconfig[tmp]->inprogressdir = defconfig.inprogressdir; + + } - if (myconfig->max == 0 && !set_max) myconfig->max = defconfig.max; - if (!myconfig->banner) myconfig->banner = defconfig.banner; - if (!myconfig->chroot) myconfig->chroot = defconfig.chroot; - if (!myconfig->game_path) myconfig->game_path = defconfig.game_path; - if (!myconfig->game_name) myconfig->game_name = defconfig.game_name; - if (!myconfig->dglroot) myconfig->dglroot = defconfig.dglroot; - if (!myconfig->rcfile) myconfig->rcfile = defconfig.rcfile; - if (!myconfig->spool) myconfig->spool = defconfig.spool; - if (!myconfig->passwd) myconfig->passwd = defconfig.passwd; - if (!myconfig->lockfile) myconfig->lockfile = defconfig.lockfile; - if (!myconfig->savefilefmt) myconfig->savefilefmt = defconfig.savefilefmt; + if (!globalconfig.chroot) globalconfig.chroot = "/var/lib/dgamelaunch/"; + + if (globalconfig.max == 0) globalconfig.max = 64000; + if (!globalconfig.dglroot) globalconfig.dglroot = "/dgldir/"; + if (!globalconfig.banner) globalconfig.banner = "/dgl-banner"; + + if (!globalconfig.shed_user && globalconfig.shed_uid == (uid_t)-1) + { + struct passwd *pw; + if ((pw = getpwnam("games"))) + globalconfig.shed_uid = pw->pw_uid; + else + globalconfig.shed_uid = 5; /* games uid in debian */ + } + + if (!globalconfig.shed_group && globalconfig.shed_gid == (gid_t)-1) + { + struct group *gr; + if ((gr = getgrnam("games"))) + globalconfig.shed_gid = gr->gr_gid; + else + globalconfig.shed_gid = 60; /* games gid in debian */ + } + } diff --git a/dgl-wall.c b/dgl-wall.c index 0888fe3..f074c6f 100644 --- a/dgl-wall.c +++ b/dgl-wall.c @@ -70,7 +70,7 @@ usage: create_config(); - if (chroot (myconfig->chroot)) + if (chroot (globalconfig.chroot)) { perror("Couldn't change root directory"); return 1; @@ -82,7 +82,7 @@ usage: return 1; } - games = populate_games (&len); + games = populate_games (-1, &len); if (len == 0) { @@ -95,10 +95,10 @@ usage: char* fname = NULL; size_t len; - len = strlen(myconfig->spool) + strlen(games[i]->name) + 2; + len = strlen(myconfig[0]->spool) + strlen(games[i]->name) + 2; fname = malloc (len + 1); - snprintf(fname, len, "%s/%s", myconfig->spool, games[i]->name); + snprintf(fname, len, "%s/%s", myconfig[0]->spool, games[i]->name); if ((spool = fopen(fname, "a")) == NULL) { diff --git a/examples/dgamelaunch.conf b/examples/dgamelaunch.conf index 431f329..dc972de 100644 --- a/examples/dgamelaunch.conf +++ b/examples/dgamelaunch.conf @@ -2,6 +2,24 @@ # are allowed, such as this. Each configuration option will be explained # along with its default value. + + +# Global config variables: + + +# Max amount of registered users to allow. +maxusers = 64000 + +# Path to a prepared chroot jail. +chroot_path = "/var/lib/dgamelaunch/" + +# From inside the jail, dgamelaunch's working directory for rcfiles/ttyrec/etc +dglroot = "/dgldir/" + +# From inside the jail, location of a banner file that contains no more than +# 14 lines of 80-column width text. Any more will be truncated. +banner = "/dgl-banner" + # The following two options are fairly insecure. They will force us to # load the password/group database into memory while still having root # privileges. Replace them with shed_uid/shed_gid entries as soon as @@ -20,29 +38,28 @@ shed_group = "games" shed_uid = 5 shed_gid = 60 -# Max amount of registered users to allow. -maxusers = 64000 -# Path to a prepared chroot jail. -chroot_path = "/var/lib/dgamelaunch/" + +# Next, we'll define one game's data: + # From inside the jail, the location of the binary to be launched. -game_path = "/bin/nethack" -game_name = "NetHack" +game_path = "/bin/nethackstub" +game_name = "NetHack stub" -# From inside the jail, dgamelaunch's working directory for rcfiles/ttyrec/etc -dglroot = "/dgldir/" +# arguments for when we exec the binary +game_args = "/bin/nethackstub" +game_args = "foo" +game_args = "user:%n" +game_args = "shed_uid:%u" +game_args = "bar" # From inside the jail, where dgamelaunch should put mail - should match up with # NetHack settings. spooldir = "/var/mail/" -# From inside the jail, location of a banner file that contains no more than -# 14 lines of 80-column width text. Any more will be truncated. -banner = "/dgl-banner" - # From inside the jail, the default .nethackrc that is copied for new users. -rc_template = "/dgl-default-rcfile" +# rc_template = "/dgl-default-rcfile" # The defaults are usually just fine for this. passwd refers to the file # that stores the user database, and lockfile is only used internally by @@ -55,4 +72,35 @@ lockfile = "/dgl-lock" # decimal representation of shed_uid, %n is replaced by the player's # user name. Before starting the game, this file is copied to its name # with ".bak" appended. Set to an empty string to disable this copying. + +savefilefmt = "/var/games/nethack/save/%u%n.gz" + +# make sure the inprogress dir actually exists. default is "inprogress/" +# each game you define here must have it's own. +inprogressdir = "inprogress/" + + + +# +# the second game +# +# +game_num = 1 + +game_path = "/bin/nethack" +game_name = "NetHack 3.4.3" + +game_args = "/bin/nethack" +game_args = "-u" +game_args = "%n" + +spooldir = "/var/mail/" +rc_template = "/dgl-default-rcfile" +# format where player rc files are saved. +# %r == dglroot +# %n == user name +rc_fmt = "%rrcfiles/%n.nethackrc" +passwd = "/dgl-login" +lockfile = "/dgl-lock" savefilefmt = "/var/games/nethack/save/%u%n.gz" +inprogressdir = "inprogress/" diff --git a/ttyrec.c b/ttyrec.c index f148c9c..274d8d0 100644 --- a/ttyrec.c +++ b/ttyrec.c @@ -82,11 +82,11 @@ struct winsize win; int uflg; int -ttyrec_main (char *username, char* ttyrec_filename) +ttyrec_main (int game, char *username, char* ttyrec_filename) { char dirname[100]; - snprintf (dirname, 100, "%sttyrec/%s/%s", myconfig->dglroot, username, + snprintf (dirname, 100, "%sttyrec/%s/%s", globalconfig.dglroot, username, ttyrec_filename); atexit(&remove_ipfile); @@ -117,11 +117,11 @@ ttyrec_main (char *username, char* ttyrec_filename) if (child) { close (slave); - ipfile = gen_inprogress_lock (child, ttyrec_filename); + ipfile = gen_inprogress_lock (game, child, ttyrec_filename); dooutput (); } else - doshell (username); + doshell (game, username); } doinput (); @@ -261,12 +261,8 @@ dooutput () } void -doshell (char *username) +doshell (int game, char *username) { - char *argv1 = myconfig->game_path; - char *argv2 = "-u"; - char *myargv[10]; - getslave (); (void) close (master); (void) fclose (fscript); @@ -275,12 +271,7 @@ doshell (char *username) (void) dup2 (slave, 2); (void) close (slave); - myargv[0] = argv1; - myargv[1] = argv2; - myargv[2] = username; - myargv[3] = 0; - - execvp (myconfig->game_path, myargv); + execvp (myconfig[game]->game_path, myconfig[game]->bin_args); fail (); } diff --git a/ttyrec.h b/ttyrec.h index 237d115..ff2b9a8 100644 --- a/ttyrec.h +++ b/ttyrec.h @@ -17,11 +17,11 @@ extern void fixtty (void); extern void getslave (void); extern void doinput (void); extern void dooutput (void); -extern void doshell (char *); +extern void doshell (int, char *); extern void finish (int); extern void remove_ipfile (void); -extern int ttyrec_main(char *username, char *ttyrec_filename); +extern int ttyrec_main(int, char *username, char *ttyrec_filename); extern pid_t child; /* nethack process */ extern int master, slave; -- 2.47.3