src/lib/player/login.c

Go to the documentation of this file.
00001 /*
00002  *  Empire - A multi-player, client/server Internet based war game.
00003  *  Copyright (C) 1986-2007, Dave Pare, Jeff Bailey, Thomas Ruschak,
00004  *                           Ken Stevens, Steve McClure
00005  *
00006  *  This program is free software; you can redistribute it and/or modify
00007  *  it under the terms of the GNU General Public License as published by
00008  *  the Free Software Foundation; either version 2 of the License, or
00009  *  (at your option) any later version.
00010  *
00011  *  This program is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  *  GNU General Public License for more details.
00015  *
00016  *  You should have received a copy of the GNU General Public License
00017  *  along with this program; if not, write to the Free Software
00018  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00019  *
00020  *  ---
00021  *
00022  *  See files README, COPYING and CREDITS in the root of the source
00023  *  tree for related information and legal notices.  It is expected
00024  *  that future projects/authors will amend these files as needed.
00025  *
00026  *  ---
00027  *
00028  *  login.c: Allow the player to login
00029  * 
00030  *  Known contributors to this file:
00031  *     Dave Pare, 1994
00032  *     Steve McClure, 2000
00033  *     Markus Armbruster, 2004-2006
00034  */
00035 
00036 #include <config.h>
00037 
00038 #include "com.h"
00039 #include "empio.h"
00040 #include "empthread.h"
00041 #include "file.h"
00042 #include "match.h"
00043 #include "misc.h"
00044 #include "nat.h"
00045 #include "nsc.h"
00046 #include "optlist.h"
00047 #include "player.h"
00048 #include "proto.h"
00049 #include "prototypes.h"
00050 
00051 static int client_cmd(void);
00052 static int coun_cmd(void);
00053 static int kill_cmd(void);
00054 static int options_cmd(void);
00055 static int pass_cmd(void);
00056 static int play_cmd(void);
00057 static int quit_cmd(void);
00058 static int sanc_cmd(void);
00059 static int user_cmd(void);
00060 
00061 static struct cmndstr login_coms[] = {
00062     {"client client-id...", 0, client_cmd, 0, 0},
00063     {"coun country", 0, coun_cmd, 0, 0},
00064     {"kill", 0, kill_cmd, 0, 0},
00065     {"options option=value...", 0, options_cmd, 0, 0},
00066     {"pass password", 0, pass_cmd, 0, 0},
00067     {"play [user [country [password]]]", 0, play_cmd, 0, 0},
00068     {"quit", 0, quit_cmd, 0, 0},
00069     {"sanc", 0, sanc_cmd, 0, 0},
00070     {"user name", 0, user_cmd, 0, 0},
00071     {0, 0, 0, 0, 0}
00072 };
00073 
00074 /*ARGSUSED*/
00075 void
00076 player_login(void *ud)
00077 {
00078     char buf[128];
00079     char space[128];
00080     int ac;
00081     int cmd;
00082 
00083     player->proc = empth_self();
00084 
00085     pr_id(player, C_INIT, "Empire server ready\n");
00086 
00087     while (!io_eof(player->iop) && !io_error(player->iop)
00088            && player->state != PS_SHUTDOWN) {
00089         io_output(player->iop, IO_WAIT);
00090         if (io_gets(player->iop, buf, sizeof(buf)) < 0) {
00091             io_input(player->iop, IO_WAIT);
00092             continue;
00093         }
00094         ac = parse(buf, space, player->argp, NULL, NULL, NULL);
00095         cmd = comtch(player->argp[0], login_coms, 0);
00096         if (cmd < 0) {
00097             pr_id(player, C_BADCMD, "Command %s not found\n", player->argp[0]);
00098             continue;
00099         }
00100         switch (login_coms[cmd].c_addr()) {
00101         case RET_OK:
00102             break;
00103         case RET_FAIL:
00104             break;
00105         case RET_SYN:
00106             pr_id(player, C_BADCMD, "Usage %s\n", login_coms[cmd].c_form);
00107             break;
00108         default:
00109             break;
00110         }
00111     }
00112     player->state = PS_SHUTDOWN;
00113     if (!io_eof(player->iop)) {
00114         pr_id(player, C_EXIT, "so long...\n");
00115         io_noblocking(player->iop, 0);
00116         while (io_output(player->iop, IO_WAIT) > 0) ;
00117     }
00118     player_delete(player);
00119     empth_exit();
00120     /*NOTREACHED*/
00121 }
00122 
00123 static int
00124 client_cmd(void)
00125 {
00126     int i, sz;
00127     char *p, *end;
00128 
00129     if (!player->argp[1])
00130         return RET_SYN;
00131 
00132     p = player->client;
00133     end = player->client + sizeof(player->client) - 1;
00134     for (i = 1; player->argp[i]; ++i) {
00135         if (i > 1)
00136             *p++ = ' ';
00137         sz = strlen(player->argp[i]);
00138         sz = MIN(sz, end - p);
00139         memcpy(p, player->argp[i], sz);
00140         p += sz;
00141     }
00142     *p = 0;
00143     pr_id(player, C_CMDOK, "talking to %s\n", player->client);
00144     return RET_OK;
00145 }
00146 
00147 static int
00148 user_cmd(void)
00149 {
00150     if (!player->argp[1])
00151         return RET_SYN;
00152     strncpy(player->userid, player->argp[1], sizeof(player->userid) - 1);
00153     player->userid[sizeof(player->userid) - 1] = '\0';
00154     pr_id(player, C_CMDOK, "hello %s\n", player->userid);
00155     return RET_OK;
00156 }
00157 
00158 static int
00159 sanc_cmd(void)
00160 {
00161     struct nstr_item ni;
00162     struct natstr nat;
00163     int first = 1;
00164 
00165     if (!opt_BLITZ) {
00166         pr_id(player, C_BADCMD, "Command %s not found\n", player->argp[0]);
00167         return RET_FAIL;
00168     }
00169 
00170     snxtitem_all(&ni, EF_NATION);
00171     while (nxtitem(&ni, &nat)) {
00172         if (nat.nat_stat != STAT_SANCT)
00173             continue;
00174         if (first) {
00175             pr_id(player, C_DATA,
00176                   "The following countries are still in sanctuary:\n");
00177             first = 0;
00178         }
00179         pr_id(player, C_DATA, "%s\n", nat.nat_cnam);
00180     }
00181     if (first)
00182         pr_id(player, C_CMDOK, "There are no countries in sanctuary\n");
00183     else
00184         pr_id(player, C_CMDOK, "\n");
00185     return RET_OK;
00186 }
00187 
00188 static int
00189 coun_cmd(void)
00190 {
00191     natid cnum;
00192 
00193     if (!player->argp[1])
00194         return RET_SYN;
00195     if (natbyname(player->argp[1], &cnum) < 0) {
00196         pr_id(player, C_CMDERR, "country %s does not exist\n", player->argp[1]);
00197         return RET_FAIL;
00198     }
00199     player->cnum = cnum;
00200     player->authenticated = 0;
00201     pr_id(player, C_CMDOK, "country name %s\n", player->argp[1]);
00202     return 0;
00203 }
00204 
00205 static int
00206 pass_cmd(void)
00207 {
00208     if (!player->argp[1])
00209         return RET_SYN;
00210     if (player->cnum == 255) {
00211         pr_id(player, C_CMDERR, "need country first\n");
00212         return RET_FAIL;
00213     }
00214     if (!natpass(player->cnum, player->argp[1])) {
00215         pr_id(player, C_CMDERR, "password bad, logging entry\n");
00216         logerror("%s tried country #%d with %s",
00217                  praddr(player), player->cnum, player->argp[1]);
00218         return RET_FAIL;
00219     }
00220     player->authenticated = 1;
00221     pr_id(player, C_CMDOK, "password ok\n");
00222     logerror("%s using country #%d", praddr(player), player->cnum);
00223     return RET_OK;
00224 }
00225 
00226 static int
00227 options_cmd(void)
00228 {
00229     /*
00230      * The option mechanism allows arbitrary string values, but so far
00231      * all options are flags in struct player.  Should be easy to
00232      * generalize if needed.
00233      */
00234     struct logoptstr {
00235         char *name;
00236         int val;
00237     };
00238     static struct logoptstr login_opts[] = {
00239         { "utf-8", PF_UTF8 },
00240         { NULL, 0 }
00241     };
00242     char **ap;
00243     char *p;
00244     int opt;
00245     unsigned i;
00246 
00247     if (!player->argp[1]) {
00248         for (i = 0; login_opts[i].name; ++i)
00249             pr_id(player, C_DATA, "%s=%d\n",
00250                   login_opts[i].name,
00251                   (player->flags & login_opts[i].val) != 0);
00252         pr_id(player, C_CMDOK, "\n");
00253         return RET_OK;
00254     }
00255 
00256     for (ap = player->argp+1; *ap; ++ap) {
00257         p = strchr(*ap, '=');
00258         if (p)
00259             *p++ = 0;
00260         opt = stmtch(*ap, login_opts,
00261                      offsetof(struct logoptstr, name),
00262                      sizeof(struct logoptstr));
00263         if (opt < 0) {
00264             pr_id(player, C_BADCMD, "Option %s not found\n", *ap);
00265             return RET_FAIL;
00266         }
00267         if (!p || atoi(p))
00268             player->flags |= login_opts[opt].val;
00269         else
00270             player->flags &= ~login_opts[opt].val;
00271     }
00272 
00273     pr_id(player, C_CMDOK, "Accepted\n");
00274 
00275     return RET_OK;
00276 }
00277 
00278 static int
00279 may_play(void)
00280 {
00281     struct natstr *np;
00282 
00283     if (player->cnum == 255 || !player->authenticated) {
00284         pr_id(player, C_CMDERR, "need country and password\n");
00285         return 0;
00286     }
00287     /* TODO strstr() cheesy, compare IP against IP/BITS ... */
00288     np = getnatp(player->cnum);
00289     if (np->nat_stat == STAT_GOD && *privip
00290         && !strstr(privip, player->hostaddr)) {
00291         logerror("Deity login from untrusted host attempted by %s",
00292                  praddr(player));
00293         logerror("To allow this, add %s to econfig key privip",
00294                  player->hostaddr);
00295         pr_id(player, C_EXIT,
00296               "Deity login not allowed from this IP!"
00297               "  See log for help on how to allow it.\n");
00298         return 0;
00299     }
00300     return 1;
00301 }
00302 
00303 static int
00304 play_cmd(void)
00305 {
00306     struct player *other;
00307     natid cnum;
00308     struct natstr *natp;
00309     char **ap;
00310 
00311     ap = player->argp;
00312     if (*++ap) {
00313         strncpy(player->userid, *ap, sizeof(player->userid) - 1);
00314         player->userid[sizeof(player->userid) - 1] = '\0';
00315         player->authenticated = 0;
00316     }
00317     if (*++ap) {
00318         if (natbyname(*ap, &cnum) < 0) {
00319             pr_id(player, C_CMDERR, "country %s does not exist\n", *ap);
00320             return RET_FAIL;
00321         }
00322     }
00323     if (*++ap) {
00324         if (!natpass(cnum, *ap)) {
00325             pr_id(player, C_CMDERR, "password bad, logging entry\n");
00326             logerror("%s tried country #%d with %s",
00327                      praddr(player), cnum, *ap);
00328             return RET_FAIL;
00329         }
00330         player->cnum = cnum;
00331         player->authenticated = 1;
00332     }
00333     if (!may_play())
00334         return RET_FAIL;
00335     other = getplayer((natid)player->cnum);
00336     if (other) {
00337         natp = getnatp(player->cnum);
00338         if (natp->nat_stat != STAT_VIS) {
00339             pr_id(player, C_EXIT, "country in use by %s\n", praddr(other));
00340         } else {
00341             pr_id(player, C_EXIT, "country in use\n");
00342         }
00343         return RET_FAIL;
00344     }
00345     logerror("%s logged in as country #%d", praddr(player), player->cnum);
00346     pr_id(player, C_INIT, "%d\n", CLIENTPROTO);
00347     player_main(player);
00348     logerror("%s logged out, country #%d", praddr(player), player->cnum);
00349     player->state = PS_SHUTDOWN;
00350     return RET_OK;
00351 }
00352 
00353 static int
00354 kill_cmd(void)
00355 {
00356     struct player *other;
00357 
00358     if (!may_play())
00359         return RET_FAIL;
00360     other = getplayer(player->cnum);
00361     if (!other) {
00362         pr_id(player, C_EXIT, "country not in use\n");
00363         return RET_FAIL;
00364     }
00365     logerror("%s killed country #%d", praddr(player), player->cnum);
00366     io_shutdown(other->iop, IO_READ | IO_WRITE);
00367     pr_id(player, C_EXIT, "closed socket of offending job\n");
00368     return RET_OK;
00369 }
00370 
00371 static int
00372 quit_cmd(void)
00373 {
00374     pr_id(player, C_EXIT, "so long\n");
00375     io_shutdown(player->iop, IO_READ);
00376     return RET_OK;
00377 }

Generated on Fri Mar 28 11:01:11 2008 for empserver by  doxygen 1.5.2