blob: bda03b5f14b79e1dba9cad2d8c4c41e6e9771bf9 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001// MorgenGrauen MUDlib
2//
3// login.c -- Object for players just logging in
4//
5// $Id: login.c 9245 2015-06-04 13:04:39Z Arathorn $
6
7 /*
8 * secure/login.c
9 *
10 * This object is cloned for every user trying to log in
11 * We are still running root.
12 *
13 * login.c looks up the username in the secure/PASSWD file. If it is
14 * found, the password is checked. If the user is already logged in,
15 * he will be reconnected to the running object. If the other object
16 * is still interactive, that will be disconnected before the user is
17 * reconnected to that object.
18 *
19 * If the user is not in PASSWD, a new entry with level 0 is created.
20 * All PASSWD writing is done in secure/master.c.
21 *
22 */
23#pragma strict_types
24#pragma no_shadow
25#pragma no_inherit
26#pragma verbose_errors
27#pragma combine_strings
28//#pragma pedantic
29//#pragma range_check
30#pragma warn_deprecated
31
32#include <config.h>
33#include <properties.h>
34#include <moving.h>
35#include "/secure/wizlevels.h"
36#include <telnet.h>
37#include <defines.h>
38#include <input_to.h>
39
40inherit "/secure/mini_props.c";
41inherit "/secure/telnetneg.c";
42
43#define SSL_GRRETING "REMOTE_HOST="
44#define PROXIES ({"127.0.0.1","87.79.24.60"})
45#define GUESTMASTER "/secure/guestmaster"
46
47#ifndef DEBUG
48#define DEBUG(x) if(find_player("tiamak")) tell_object(find_player("tiamak"),x)
49#define DEBUGM(x) if(find_player("muadib")) tell_object(find_player("muadib"),x)
50#endif
51
52/* Variables of the secure save file */
53int level, loginfails, creation_date;
54string password, name, shell, ep, ek, mq;
55string ektips;
56string fptips;
57string *domains, *guilds, *uidstotakecare;
58
59static int invis, neu;
60static string loginname;
61static string cap_name;
62static string *userentry;
63static string banish;
64static mixed *races;
65static int newbie;
66static string realip;
67
68// Prototypes
69static void SendTelopts();
70public nomask string loginname();
71// the following 4 lfuns deal with real logins
72public nomask int logon();
73static int logon2( string str );
74static int load_player_object( int guestflag );
75static void load_player_ob_2( string obname, int guestflag );
76static int check_illegal( string str );
77static int valid_name( string str );
78static int new_password( string str );
79static int again_password( string str );
80static int check_password( string str );
81static void select_race();
82static void ask_race_question();
83static void get_race_answer( string str );
84
85protected void create();
86public string short();
87public string query_real_name();
88public nomask int query_prevent_shadow();
MG Mud User88f12472016-06-24 23:31:02 +020089public int remove();
90// the following 3 lfuns deal with dummy player creation
91public mixed new_logon( string str);
92static mixed new_load_player_object();
93static mixed new_load_player_ob_2( string obname );
94static void ask_mud_played_question();
95static void get_mud_played_answer(string str);
96
97
98public nomask string loginname()
99{
100 return loginname ? loginname : "";
101}
102
103
104public int remove()
105{
106 destruct( this_object() );
107 return 1;
108}
109
110
111static int check_too_many_logons()
112{
113 object *u;
114 string ip;
115
116 ip = query_ip_number(this_object());
117 // users() nehmen, falls nicht-interaktive Clones von login.c existieren.
118 u = filter( users(), function status (object ob, string addr) {
Zesstra077f3c62016-09-30 21:24:05 +0200119 return load_name(ob) == "/secure/login"
MG Mud User88f12472016-06-24 23:31:02 +0200120 && query_ip_number(ob) == addr;
121 }, ip );
122
Zesstracb45e3d2016-09-30 20:13:31 +0200123 if ( sizeof(u) > 2) {
MG Mud User88f12472016-06-24 23:31:02 +0200124 write( "\nEs laufen schon zu viele Anmeldungen von Deiner Adresse "
125 "aus.\nProbier es bitte in ein bis zwei Minuten noch "
126 "einmal.\n" );
127
Zesstracb45e3d2016-09-30 20:13:31 +0200128 log_file( "LOGIN_DENY", sprintf( "%s: >2 Logons von %-15s (%s)\n",
MG Mud User88f12472016-06-24 23:31:02 +0200129 ctime(time())[4..15],
130 query_ip_number(this_object()),
131 query_ip_name(this_object()) ) );
132 return 1;
133 }
134 else
135 return 0;
136}
137
138
139/*
140 * This is the function that gets called by /secure/master for every user
141 */
142public nomask int logon()
143{
144 loginname = "logon";
145 newbie=0;
146 realip="";
147
148 // als erstes wird ein Lookup gemacht, ob die Quelladresse ein
149 // Tor-Exitnode ist, der erlaubt, zu uns zu kommunizieren. Das Lookup ist
150 // asynchron und braucht eine Weile, wenn das Ergebnis noch nicht gecacht
151 // ist. An dieser Stelle wird das Ergebnis nicht ausgewertet. Achja, wie
152 // machen das natuerlich nicht fuer die IP vom Mudrechner...
153 if (query_ip_number(this_object()) != "87.79.24.60")
154 {
155 "/p/daemon/dnslookup"->check_tor(query_ip_number(this_object()),query_mud_port());
156 "/p/daemon/dnslookup"->check_dnsbl(query_ip_number(this_object()));
157 }
158 printf("HTTP/1.0 302 Found\n"
159 "Location: http://mg.mud.de/\n\n"
160 "NetCologne, Koeln, Germany. Local time: %s\n\n"
161 MUDNAME" LDmud, NATIVE mode, driver version %s\n\n",
162 strftime("%c"), __VERSION__);
163
164 SendTelopts();
165
166 if ( check_too_many_logons() ){
167 destruct(this_object());
168 return 0;
169 }
170
171 // ist die Verbindung schon wieder weg?
172 if (objectp(this_object()) && interactive(this_object())) {
173 cat( "/etc/WELCOME" );
174 }
175
176 input_to( "logon2", INPUT_PROMPT,
177 "Wie heisst Du denn (\"neu\" fuer neuen Spieler)? ");
Zesstra28d72e52016-10-27 23:56:19 +0200178 set_next_reset(300);
MG Mud User88f12472016-06-24 23:31:02 +0200179 return 1;
180}
181
182
183static int check_too_many_from_same_ip()
184{
185 object *u;
186 string ip;
187
188 ip = query_ip_number(this_object());
189 u = filter(users(), function status (object ob, string addr, int a) {
190 return query_ip_number(ob) == addr
191 && ob->QueryProp(P_AGE) < a;
192 }, ip, 12*60*60); // 24h in heart_beats
193
194 if ( sizeof(u) > 25 ){
195 write( "\nDa anscheinend gerade jemand von Deiner Adresse aus "
196 "versucht, das \n"MUDNAME" mit neuen Charakteren zu "
197 "ueberschwemmen, werden momentan \nnur aeltere Charaktere "
198 "von dieser Adresse zugelassen.\nWenn Du meinst, dass es "
199 "sich um einen Fehler handelt, logg Dich bitte als \n"
200 "Gast ein und sprich einen Erzmagier oder Gott an.\n" );
201
202 log_file( "LOGIN_DENY", sprintf( "%s: >10 Spieler von %-15s (%s)\n",
203 ctime(time())[4..15],
204 query_ip_number(this_object()),
205 query_ip_name(this_object()) ) );
206
207 destruct(this_object());
208 return 1;
209 }
210 else
211 return 0;
212}
213
214
215static int check_illegal( string str )
216{
217 string res;
218
219 res = (string)master()->QuerySBanished(query_ip_number(this_object()));
220 if (!res)
221 {
222 // check connection from Tor exit node
223 string eff_ip = (realip!="" ? realip : query_ip_number(this_object()));
224 if ("/p/daemon/dnslookup"->check_tor(eff_ip, query_mud_port())
225 || "/p/daemon/dnslookup"->check_dnsbl(eff_ip))
226 res =
227 "\nSorry, von Deiner Adresse kamen ein paar Idioten, die "
228 "ausschliesslich\nAerger machen wollten. Deshalb haben wir "
229 "die Moeglichkeit,\neinfach neue Charaktere "
230 "anzulegen, fuer diese Adresse gesperrt.\n\n"
231 "Falls Du bei uns spielen moechtest, schicke bitte eine Email "
232 "an\n\n mud@mg.mud.de\n\n"
233 "mit der Bitte, einen Charakter fuer Dich anzulegen.\n" ;
234 }
235
236 if ( res )
237 {
238 write( res );
239 log_file( "LOGIN_DENY", sprintf( "%s: %-11s %-15s (%s)\n",
240 ctime(time())[4..15], str,
241 query_ip_number(this_object()),
242 query_ip_name(this_object()) ) );
243 remove();
244 return 1;
245 }
246
247 return 0;
248}
249
250
251/*
252 * Check that a player name is valid. Only allow
253 * lowercase letters.
254 */
255static int valid_name( string str )
256{
257 int i;
258
259 if ( str == "logon" ){
260 write( "Der Name wuerde nur Verwirrung stiften.\n" );
261 return 0;
262 }
263
264 i = sizeof(str);
265
266 if ( i > 11 ){
267 write( "Dein Name ist zu lang, nimm bitte einen anderen.\n" );
268 return 0;
269 }
270
271 for ( ; i--; )
272 if ( str[i] < 'a' || str[i] > 'z' ) {
273 write( "Unerlaubtes Zeichen '" + str[i..i] + "' im Namen: " + str
274 + "\n" );
275 write( "Benutze bitte nur Buchstaben ohne Umlaute.\n" );
276 return 0;
277 }
278
279 return 1;
280}
281
282
283static int logon2( string str )
284{
285 int i, arg;
286 mixed txt;
287
288 if ( !str || str == "" ){
289 write( "Abbruch!\n" );
290 destruct( this_object() );
291 return 0;
292 }
293
294 // Unterstuetzung fuer das Mud Server Status Protocol
295 // (http://tintin.sourceforge.net/mssp/)
296#ifdef MSSP_SUPPORT
297 if (str == "MSSP-REQUEST") {
298 "/secure/misc/mssp"->print_mssp_response();
299 log_file( "MSSP.log", sprintf( "%s: %-15s (%s)\n",
300 strftime("%c"),
301 query_ip_number(this_object()),
302 query_ip_name(this_object())||"N/A" ) );
303 input_to("logon2", INPUT_PROMPT,
304 "Wie heisst Du denn (\"neu\" fuer neuen Spieler)? ");
305 return 1;
306 }
307#endif
308
309 if(strstr(str,SSL_GRRETING)==0)
310 {
311 if( member(PROXIES,query_ip_number(this_object()))>-1 )
312 {
313 realip=str[sizeof(SSL_GRRETING)..];
314 } // andere IPs werden einfach ignoriert. -> log/PROXY.REQ ?
315 // ggf. Lookup fuer Torexits anstossen.
316 "/p/daemon/dnslookup"->check_tor(realip,query_mud_port());
317 "/p/daemon/dnslookup"->check_dnsbl(realip);
318
319 input_to( "logon2", INPUT_PROMPT,
320 "Wie heisst Du denn (\"neu\" fuer neuen Spieler)? ");
321 return 1;
322 }
323
324 if ( loginname != "logon" ) {
325 log_file( "ILLEGAL", sprintf( "%s Illegal patch of login: "
326 "loginname = %O\n",
327 dtime(time()), loginname ) );
328 destruct( this_object() );
329 return 0;
330 }
331
332 str = lower_case(str);
333 cap_name = capitalize(str);
334
335 if ( str == "neu" && !neu ){
336 cat( "/etc/WELCOME_NEW" );
337 neu = 1;
338 input_to( "logon2", INPUT_PROMPT, "Name: ");
339 return 1;
340 }
341
342 if ( !valid_name(str) ){
343 string pr;
344 if ( !neu )
345 pr= "Wie heisst Du denn (\"neu\" fuer neuen Spieler)? ";
346 else
347 pr= "Bitte gib Dir einen anderen Namen: ";
348
349 input_to( "logon2", INPUT_PROMPT, pr );
350 return 1;
351 }
352
353 if ( sscanf( str, "gast%d", arg ) == 1 ){
354 write( "Du meinst wohl 'Gast' ...\n" );
355 str = "gast";
356 }
357
358 loginname = str;
359
360 /* read the secure save file to see if character already exists */
Zesstra313eee92017-01-31 14:55:08 +0100361 string ssavef=master()->secure_savefile(loginname);
362 if ( loginname != "gast"
363 && (!ssavef || !sizeof(ssavef) || !restore_object(ssavef) ))
Zesstrae43dd602017-01-31 10:48:10 +0100364 {
MG Mud User88f12472016-06-24 23:31:02 +0200365 object *user;
366
367 if ( !neu )
368 {
369 write( "Es existiert kein Charakter mit diesem Namen.\n" );
370 write( "Falls Du einen neuen Charakter erschaffen moechtest, "
371 "tippe bitte \"neu\" ein.\n" );
372
373 loginname = "logon";
374 input_to( "logon2", INPUT_PROMPT,
375 "Wie heisst Du denn (\"neu\" fuer neuen Spieler)? ");
376 return 1;
377 }
378
379 for ( i = sizeof(user = users() - ({ 0, this_object() })); i--; )
380 if ( object_name(user[i])[0..12] == "/secure/login" &&
381 ((string)user[i]->loginname()) == loginname ){
382 write( "Eine Anmeldung fuer diesen Namen laeuft bereits.\n" );
383 destruct( this_object() );
384 return 1;
385 }
386
387 // Site-Banish checken
388 if ( check_illegal(loginname))
389 return 1;
390
391 if ( check_too_many_from_same_ip() )
392 return 1;
393
394 /* new character */
395 if ( sizeof(loginname) < 3 ){
396 write( "Der Name ist zu kurz.\n" );
397 loginname = "logon";
398 input_to( "logon2", INPUT_PROMPT,
399 "Versuch einen anderen Namen: ");
400 return 1;
401 }
402
403
404 if ( (txt = (string)master()->QueryBanished(loginname)) ){
405 if ( txt != "Dieser Name ist gesperrt." )
406 txt = sprintf("Hoppla - dieser Name ist reserviert oder gesperrt "
407 "(\"gebanisht\")!\nGrund: %s\n",txt);
408 else
409 txt = "Hoppla - dieser Name ist reserviert oder gesperrt "
410 "(\"gebanisht\")!\n";
411 write(txt);
412 loginname = "logon";
413 input_to( "logon2", INPUT_PROMPT,
414 "Bitte gib Dir einen anderen Namen: ");
415 return 1;
416 }
417
418 /* Initialize the new secure savefile */
419 name = loginname;
420 password = "";
421 level = 0;
422 domains = ({ });
423 guilds = ({ });
424 shell = "";
425 ep = "";
426 ek = "";
427 mq = "";
428 ektips="";
429 fptips="";
430 creation_date = time();
431
432 input_to( "new_password", INPUT_NOECHO|INPUT_PROMPT,
433 "Waehle ein Passwort: ");
434 return 1;
435 }
436 else {
437 if ( loginname == "gast" ){
438 if ( check_illegal(loginname) )
439 return 1;
440
441 load_player_object(1);
442 return 1;
443 }
444
445 if ( neu ){
446 write( "Es existiert bereits ein Charakter dieses Namens.\n" );
447 loginname = "logon";
448 input_to( "logon2", INPUT_PROMPT,
449 "Gib Dir einen anderen Namen: ");
450 return 1;
451 }
452
453 if ( (int)master()->check_late_player(loginname) )
454 {
455 write( "Dieser Spieler hat uns leider fuer immer verlassen.\n" );
456 loginname = "logon";
457 input_to( "logon2", INPUT_PROMPT,
458 "Wie heisst Du denn (\"neu\" fuer neuen Spieler)? ");
459 return 1;
460 }
461
462 if ( txt = (string)master()->QueryTBanished(loginname) ){
463 write( txt );
464 loginname = "logon";
465 input_to( "logon2", INPUT_PROMPT,
466 "Wie heisst Du denn (\"neu\" fuer neuen Spieler)? ");
467 return 1;
468 }
469
470 if ( creation_date > (time() - 30*24*60*60)
471 && check_too_many_from_same_ip() )
472 return 1;
473
474 write( "Schoen, dass Du wieder da bist, "+capitalize(loginname)+"!\n" );
475
476 if ( !stringp(password) || password == "" ) {
477 write( "Du hast KEIN PASSWORD!\n" );
478 write( "Benutze den \"password\"-Befehl, um das zu aendern !\n" );
479 load_player_object(0);
480 return 1;
481 }
482
483 input_to( "check_password", INPUT_NOECHO|INPUT_PROMPT,
484 "Passwort: ");
485 return 1;
486 }
487}
488
489
490static int new_password( string str )
491{
492 write( "\n" );
493
494 if ( !str || str == "" )
495 return remove();
496
497 password = str;
498
499 if ( !master()->good_password( str, loginname ) ) {
500 input_to( "new_password", INPUT_NOECHO|INPUT_PROMPT,
501 "Bitte gib ein Passwort an: ");
502 return 1;
503 }
504
505 write( "\nZur Erinnerung: Es ist v e r b o t e n, andere Spieler "
506 "anzugreifen!\n" );
507 write( "Das gilt auch fuer Froesche, bei denen \"Ein Frosch namens "
508 "XXXXX\" steht.\n\n" );
509 input_to( "again_password", INPUT_NOECHO|INPUT_PROMPT,
510 "Passwort bitte nochmal eingeben: ");
511 return 1;
512}
513
514static int again_password( string str )
515{
516 write( "\n" );
517
518 if ( str != password ){
519 write( "Die Passwoerter stimmten nicht ueberein!\n" );
520 destruct( this_object() );
521 return 1;
522 }
523
Zesstra28d72e52016-10-27 23:56:19 +0200524 set_next_reset(600);
MG Mud User88f12472016-06-24 23:31:02 +0200525 password = md5_crypt( password, 0 );
526 save_object( SECURESAVEPATH + loginname[0..0] + "/" + loginname );
527 master()->RemoveFromCache( loginname );
528
529 load_player_object(0);
530 return 1;
531}
532
533static int check_password( string str )
534{
535 write( "\n" );
536
537 // Invis einloggen?
538 if (sizeof(str) > 1 && str[0] == '-') {
539 invis = 1;
540 str = str[1..];
541 }
542
543 // welcher Hash ists denn?
544 if (sizeof(password) > 13) {
545 // MD5-Hash
546 str = md5_crypt(str, password);
547 }
548 else if (sizeof(password) > 2) {
549 // Crypt-Hash
550 str = crypt(str, password[0..1]);
551 }
552 else {
553 // keiner von beiden Hashes -> ungueltiges PW
554 str = 0;
555 }
556
557 if ( !stringp(str) || str != password ) {
558 // Hashes stimmen nicht ueberein -> und schluss...
559 write( "Falsches Passwort!\n");
560 if ( loginfails > 2 )
561 write(break_string(
562 "Solltest Du weiterhin Probleme mit dem Einloggen haben, kannst "
563 "Du Dein Passwort zuruecksetzen lassen, indem Du Dich als Gast "
564 "anmeldest und einen Erzmagier ansprichst, oder indem Du Dich "
Zesstra0559c662017-02-06 19:14:51 +0100565 "mittels einer E-Mail an mud@mg.mud.de mit uns in Verbindung "
MG Mud User88f12472016-06-24 23:31:02 +0200566 "setzt.",78));
567
568 log_file( (level < 60 ? "LOGINFAIL" : "ARCH/LOGINFAIL"),
569 sprintf( "PASSWORD: %-11s %s, %-15s (%s)\n",
570 loginname, ctime(time())[4..15],
571 query_ip_number(this_object()),
572 query_ip_name(this_object()) ), 200000 );
573
574 loginfails++;
575 save_object( SECURESAVEPATH + loginname[0..0] + "/" + loginname );
576 master()->RemoveFromCache( loginname );
577 destruct( this_object() );
578 return 1;
579 }
580
581 if ( loginfails ) {
582 write( loginfails + " fehlgeschlagene" + (loginfails == 1 ? "r" : "") +
583 " Login-Versuch" + (loginfails == 1 ? "" : "e") +
584 " seit dem letzten erfolgreichen Login.\n" );
585 loginfails = 0;
586 }
587
588 save_object( SECURESAVEPATH + loginname[0..0] + "/" + loginname );
589 master()->RemoveFromCache( loginname );
590
591 load_player_object(0);
592 return 1;
593}
594
595
596static void select_race()
597{
598 int i;
Zesstra7e353662019-11-27 19:52:41 +0100599 string race;
600 int selectable;
MG Mud User88f12472016-06-24 23:31:02 +0200601
602 races = get_dir( "/std/shells/*.c" );
603
604 // Mensch soll immer als erstes in der Auswahlliste stehen.
605 if (member(races,"human.c")!=-1)
606 races=({"human.c"})+(races-({"human.c"}));
607
608 for ( i = sizeof(races); i--; ){
609 races[i] = "/std/shells/" + races[i][0..<3];
Zesstra7e353662019-11-27 19:52:41 +0100610 selectable = 0;
611 race = 0;
612 if ( catch(selectable = ({int})call_other( races[i],
613 "QueryAllowSelect" ); publish)
614 || !selectable)
615 selectable = 0;
616 else if ( catch(race = ({string})call_other(races[i],
617 "QueryProp", P_RACE );publish) )
618 race = 0;
MG Mud User88f12472016-06-24 23:31:02 +0200619
Zesstra7e353662019-11-27 19:52:41 +0100620 if ( !selectable || !sizeof(race) )
MG Mud User88f12472016-06-24 23:31:02 +0200621 races[i..i] = ({});
622 else
Zesstra7e353662019-11-27 19:52:41 +0100623 races[i] = ({ races[i], race });
MG Mud User88f12472016-06-24 23:31:02 +0200624 }
625
626 if ( sizeof(races) == 1 ){
627 write( "Es gibt nur eine Rasse, Du hast also keine Wahl.\n" );
628
629 shell = races[0][0];
630 master()->set_player_object( loginname, shell );
631
632 return load_player_ob_2( shell, 0 );
633 }
634
635 return ask_mud_played_question();
636}
637
638static void ask_mud_played_question()
639{
640 write(break_string(
641 "\nWenn Du ein absoluter Neuling in diesem Spiel bist moechten "
642 "wir Dir mit einigen Tips zu Beginn beiseite stehen.\n\n",78,
643 0,BS_LEAVE_MY_LFS));
644 input_to( "get_mud_played_answer", INPUT_PROMPT,
645 "Hast Du schon einmal in einem MUD gespielt? (ja,nein): ");
646 return;
647}
648
649static void ask_race_question()
650{
651 int i, j;
652
653 write( break_string( "Du musst Dich jetzt entscheiden, welcher Rasse Du "
654 "in dieser Welt angehoeren moechtest. Alle Rassen "
655 "haben verschiedene Vor- und Nachteile, insgesamt "
656 "aber gleich gute Chancen. Auch das Startgebiet "
657 "haengt von der ausgewaehlten Rasse ab. Im "
658 "Normalfall kann die Rasse nicht mehr gewechselt "
659 "werden, nachdem sie einmal ausgewaehlt wurde. "
660 "Ueberlege Dir Deine Entscheidung also gut. Derzeit "
661 "stehen folgende Rassen zur Auswahl:\n\n", 78 ) );
662
663 for ( i = 0, j = sizeof(races); i < j; i++ )
664 printf( "% 2d. %-30s %s", i+1, capitalize(races[i][1]),
665 (i % 2 ? "\n" : "| ") );
666
667 if ( sizeof(races) % 2 )
668 write( "\n" );
669
670 write( break_string( "\nDurch Eingabe einer Ziffer waehlst Du die Rasse "
671 "aus, durch Eingabe eines \"\?\" gefolgt von einer "
672 "Ziffer erhaeltst Du naehere Informationen ueber "
673 "eine Rasse. Ein \"\?\" allein wiederholt diese "
674 "Liste.", 78, 0, 1 ) );
675
676 if (newbie)
677 {
678 write(break_string("\nAls Neuling solltest Du Dich NICHT fuer "
679 "die Dunkelelfen entscheiden. Diese "
680 "Rasse hat einige Probleme im Umgang "
681 "mit den anderen Rassen und mit dem "
682 "Sonnenlicht.",78,0,BS_LEAVE_MY_LFS));
683 }
684
685 input_to( "get_race_answer", INPUT_PROMPT,
686 "\nWas willst Du tun: ");
687 return;
688}
689
690
691static void get_race_answer( string str )
692{
693 int num;
694
695 if ( str == "?" )
696 return ask_race_question();
697
698 if ( sscanf( str, "?%d", num ) ){
699 if ( num < 1 || num > sizeof(races) ){
700 write( "Das geht nicht.\n\n");
701 input_to( "get_race_answer", INPUT_PROMPT,
702 "Was willst Du tun: ");
703 return;
704 }
705
706 write( call_other( races[num - 1][0], "QueryProp", P_RACE_DESCRIPTION ));
707 input_to( "get_race_answer", INPUT_PROMPT,
708 "\nWas willst Du tun: ");
709 return;
710 }
711
712 if ( sscanf( str, "%d", num ) && num >= 1 && num <= sizeof(races) ){
713 write( "Ok, Du bist jetzt ein "
714 + capitalize(races[num-1][1]) + ".\n" );
715
716 shell = races[num-1][0];
717 master()->set_player_object( loginname, shell );
718 return load_player_ob_2( shell, 0 );
719 }
720
721 write("Wie bitte?\n\n" );
722 input_to( "get_race_answer", INPUT_PROMPT,
723 "Was willst Du tun: ");
724}
725
726static void get_mud_played_answer (string str)
727{
728 if ( str == "ja" || str=="j")
729 {
730 newbie=0;
731 return ask_race_question();
732 }
733 if ( str != "nein" && str!="n")
734 {
735 write("\n\nAntworte bitte mit ja oder nein.\n\n");
736
737 return ask_mud_played_question();
738 }
739 newbie=1;
740 write("\n\nEine kleine Einfuehrung in das "MUDNAME" bekommst "
741 "Du auch hier:\n\n"
742 "http://mg.mud.de/newweb/hilfe/tutorial/inhalt.shtml\n\n");
743 return ask_race_question();
744
745}
746
747static int load_player_object( int guestflag )
748{
749 object ob;
750 string fname;
751 int was_interactive;
752
753 if ( sizeof(users()) >= 195 && !IS_WIZARD(loginname) ){
754 write( "Die maximale Spielerzahl wurde bereits erreicht!!!\n"
755 "Aus technischen Gruenden duerfen sich nur noch Magier "
756 "einloggen.\nVersuch es spaeter noch einmal ...\n" );
757 destruct( this_object() );
758 return 1;
759 }
760 else if ( sizeof(users()) >= 198 && !IS_ARCH(loginname) ){
761 write( "Die maximale Spieler- und Magierzahl wurde bereits erreicht!!!"
762 "\nAus technischen Gruenden duerfen sich nur noch Erzmagier "
763 "einloggen.\nVersuch es spaeter noch einmal ...\n" );
764 destruct( this_object() );
765 return 1;
766 }
767
768 if ( file_size("/etc/NOLOGIN")>=0 )
769 {
770 if (file_size("/etc/NOLOGIN.info")>0) {
771 //NOLOGIN.info enthaelt evtl. weitergehende Informationen fuer
772 //Spieler, z.B. vorrauss. Wiederverfuegbarkeit.
773 write(break_string(read_file("/etc/NOLOGIN.info"),78,"",
774 BS_LEAVE_MY_LFS|BS_SINGLE_SPACE));
775 }
776 else {
777 //sonst Standardmeldung ausgeben.
778 write ("\nAufgrund von technischen Problemen ist das Einloggen ins "
779 MUDNAME" zur \nZeit nicht moeglich. Bitte versuch es "
780 "spaeter noch einmal.\n\n");
781 }
782 if ( IS_ARCH(loginname) ||
783 member(explode(read_file("/etc/NOLOGIN")||"","\n"),
784 loginname)!=-1 )
785 {
786 write("Im Moment koennen nur Erzmagier einloggen. Um Spieler "
787 "wieder ins Spiel zu lassen, muss die Datei '/etc/NOLOGIN' "
788 "geloescht werden.\n\n ");
789 } else {
790 destruct( this_object() );
791 return 1;
792 }
793 }
794
795 if ( guestflag ){
796 if ( catch(guestflag = (int)GUESTMASTER->new_guest();publish)
797 || !guestflag ){
798 write( "Derzeit ist kein Gastlogin moeglich!\n" );
799 destruct( this_object() );
800 return 1;
801 }
802
803 loginname = "gast" + guestflag;
804 cap_name = capitalize(loginname);
805 name = cap_name;
806
807 if ( !(ob = find_player(loginname) || find_netdead(loginname)) ){
808 object *user;
809 int i;
810
811 // gegen Horden von Gast1 - wenn ein Gast noch am Prompt fuer
812 // das Geschlecht haengt, ist er ueber find_player() noch nicht
813 // zu finden ...
814 for ( i = sizeof(user = users() - ({ 0, this_object() })); i--; )
815 if ( object_name(user[i])[0..11] == "/std/shells/" &&
816 getuid(user[i]) == loginname ){
817 ob = user[i];
818 break;
819 }
820 }
821
822 if ( ob ){
823 tell_object( ob, "Ein anderer Spieler moechte diesen Gastzugang "
824 "jetzt benutzen. Wenn es Dir hier\ngefallen hat, "
825 "ueberleg Dir doch einen Charakternamen und komm "
826 "unter diesem\nNamen wieder!\n" );
827 destruct(ob);
828 }
829
830 load_player_ob_2( "std/shells/human", guestflag );
831
832 return 1;
833 }
834 else {
835 /* Test if we are already playing */
836 was_interactive = 0;
837 ob = find_player(loginname) || find_netdead(loginname);
838
839 if (ob) {
840 write( "Du nimmst schon am Spiel teil!\n" );
841 write( "Verwende Deine alte sterbliche Huelle ...\n" );
842
843 if ( interactive(ob) )
844 {
845 /* The other object is still interactive; reconnect that "soul"
846 to a dummy object and destruct that, thus disconnecting the
847 other probably linkdead user. The real "body" is still
848 there for reconnecting by login.c */
849 remove_interactive(ob);
850 was_interactive = 1;
851 }
852 // Wenn Invislogin, P_INVIS setzen.
853 if ( invis && IS_WIZARD(ob) )
854 {
855 ob->SetProp( P_INVIS, ob->QueryProp(P_AGE) );
856 tell_object( ob, "DU BIST UNSICHTBAR!\n" );
857 }
858 /* Now reconnect to the old body */
859 exec( ob, this_object() );
860 ob->set_realip(realip);
861 if ( ((int)ob->QueryProp(P_LEVEL)) == -1 )
862 ob->start_player( cap_name );
863 else
864 ob->Reconnect( was_interactive );
865
866 call_out( "remove", 2 );
867 return 1;
868 }
869 }
870
871 /* read player object from passwd file */
872 if ( stringp(shell) && shell != "" )
873 load_player_ob_2 ( shell, 0 );
874 else
875 select_race();
876
877 return 1;
878}
879
880
881static void load_player_ob_2( string obname, int guestflag )
882{
883 object blueprint;
884 string err, ob_name;
885 object ob, old_ob;
886
887 if (!interactive()) {
888 destruct(this_object());
889 return;
890 }
891 /* start player activity */
Zesstrae88826c2016-09-24 20:37:05 +0200892 log_file( "syslog/shell/ENTER", sprintf( "%-11s %s, %-15s (%s).\n",
MG Mud User88f12472016-06-24 23:31:02 +0200893 capitalize(name), ctime(time())[4..15],
894 query_ip_number(this_object()),
895 query_ip_name(this_object()) ), 200000 );
896
897 seteuid(loginname);
898
899 /* load the "real" player object */
900 /* If some asshole has moved the blueprint */
901 if ( objectp(blueprint = find_object(obname)) && environment(blueprint) )
902 destruct(blueprint);
903
904 if ( err = catch(ob = clone_object(obname);publish) ){
905 log_file( "SHELLS", "Failed to load shell " + obname + ", " +
906 dtime(time()) + ", " + loginname + "\n" + err + "\n\n" );
907
908 write( "Konnte das passende Playerobjekt nicht laden. Lade "
909 "stattdessen\ndas Objekt Mensch. BITTE ERZMAGIER "
910 "BENACHRICHTIGEN !\n" );
911 err = catch(ob = clone_object("/std/shells/human");publish);
912 }
913
914 if ( !ob || err ) {
915 write( "Error on loading " + shell + "\nError = " + err + "\n" );
916 destruct( this_object() );
917 return;
918 }
919
920 if ( guestflag )
921 catch( GUESTMASTER->set_guest( guestflag, ob );publish );
922
923 ob_name = explode( object_name(ob), "#" )[0];
924
925 if ( sizeof(ob_name) > 11 && ob_name[0..11] == "/std/shells/" )
926 ob_name = ob_name[11..];
927
928 ob_name = ob_name + ":" + loginname;
929
930 if( !guestflag )
931 {
932 if ( old_ob = find_object(ob_name) )
933 {
934 catch(old_ob->remove();publish);
935
936 if ( old_ob )
937 destruct( old_ob );
938 }
939 rename_object( ob, ob_name );
940 ob->__reload_explore();
941 }
942 exec( ob, this_object() );
943 ob->set_realip(realip);
944 ob->start_player( cap_name );
Zesstraab834bb2020-01-21 13:11:45 +0100945 // Hinweis: Das Spielerobjekt holt sich in updates_after_restore() von hier
946 // den Status von invis und setzt ggf. P_INVIS, ausserdem den Status der
947 // Telnet Negotiations.
MG Mud User88f12472016-06-24 23:31:02 +0200948
MG Mud User88f12472016-06-24 23:31:02 +0200949 // wenn der Spieler noch nicht im Mud gespielt hat, wird die aktuelle Zeit
950 // in die entsprechende Prop geschrieben. Die Prop ist transient und wird
951 // absichtlich nicht gespeichert.
952 if (newbie)
953 ob->SetProp("_lib_mud_newbie", creation_date);
954
955 destruct( this_object() );
956}
957
958
959/*
960 * With arg = 0 this function should only be entered once!
961 */
962protected void create()
963{
964 loginname = "logon";
965 creation_date = -1;
966 catch( load_object( "/secure/merlin");publish );
967 loginfails = 0;
968 realip="";
969 if (clonep())
970 set_next_reset(900);
971 else
972 set_next_reset(-1);
973}
974
975void reset()
976{
977 if (clonep())
Zesstra28d72e52016-10-27 23:56:19 +0200978 {
979 if (interactive(this_object()))
980 tell_object(this_object(),"Time out!");
MG Mud User88f12472016-06-24 23:31:02 +0200981 remove();
Zesstra28d72e52016-10-27 23:56:19 +0200982 }
MG Mud User88f12472016-06-24 23:31:02 +0200983}
984
985public string short()
986{
987 return "<Einloggender Teilnehmer>.\n";
988}
989
990
991public string query_real_name()
992{
993 return "<logon>";
994}
995
996
997public nomask int query_prevent_shadow()
998{
999 return 1;
1000}
1001
1002
MG Mud User88f12472016-06-24 23:31:02 +02001003// Wird von simul_efuns benutzt, um nen dummy-Spielerobjekt zu erzeugen. Nicht
1004// im Loginprozess involviert.
1005public mixed new_logon( string str)
1006{
1007 seteuid(getuid()); // sonst funkt ARCH_SECURITY nicht
1008
1009 if ( !ARCH_SECURITY || process_call() ){
1010 write( "Nur fuer Erzmagier erlaubt!\n" );
1011 destruct( this_object() );
1012 return -1;
1013 }
1014
1015 if ( !str || str == "" ){
1016 write( "Kein Name angegeben!\n" );
1017 destruct( this_object() );
1018 return 0;
1019 }
1020
1021 str = lower_case(str);
1022 cap_name = capitalize(str);
1023
1024 loginname = str;
1025 seteuid(ROOTID);
1026
1027 /* read the secure save file to see if character already exists */
1028 if ( !restore_object( master()->secure_savefile(loginname) ) ){
1029 write( "Kein solcher Spieler!\n" );
1030 destruct( this_object() );
1031 return 0;
1032 }
1033 else {
1034 write( "Ok, der Spieler " + capitalize(str) + " existiert!\n" );
1035 return new_load_player_object();
1036 }
1037}
1038
1039// Wird von simul_efuns benutzt, um nen dummy-Spielerobjekt zu erzeugen. Nicht
1040// im Loginprozess involviert.
1041static mixed new_load_player_object()
1042{
1043 if ( find_player(loginname) || find_netdead(loginname) ){
1044 write( "Der Spieler ist bereits online oder netztot!\n" );
1045 destruct( this_object() );
1046 return 2;
1047 }
1048
1049 /* read player object from passwd file */
1050 if ( stringp(shell) && shell != "" )
1051 return new_load_player_ob_2( shell );
1052 else {
1053 write( "Keine Shell angegeben!\n" );
1054 destruct( this_object() );
1055 return 0;
1056 }
1057}
1058
1059// Wird von simul_efuns benutzt, um nen dummy-Spielerobjekt zu erzeugen. Nicht
1060// im Loginprozess involviert.
1061static mixed new_load_player_ob_2( string obname )
1062{
1063 object blueprint;
1064 string err, ob_name;
1065 object ob, old_ob;
1066
1067 seteuid(loginname);
1068
1069 /* load the "real" player object */
1070 /* If some asshole has moved the blueprint */
1071 if ( objectp(blueprint = find_object(obname)) && environment(blueprint) )
1072 destruct( blueprint );
1073
1074 err = catch(ob = clone_object(obname);publish);
1075
1076 if ( err ){
1077 log_file( "SHELLS", "Failed to load shell " + obname + ", " +
1078 dtime(time()) + ", " + loginname + "\n" + err + "\n\n" );
1079
1080 write( "Konnte das passende Playerobjekt nicht laden. "
1081 "Lade stattdessen\ndas Objekt Mensch!\n" );
1082
1083 err = catch(ob = clone_object( "std/shells/human" );publish );
1084 }
1085
1086 if ( !ob || err ){
1087 write( "Error on loading " + shell + "\nError = " + err + "\n" );
1088 destruct( this_object() );
1089 return 0;
1090 }
1091
1092 ob_name = explode( object_name(ob), "#" )[0];
1093
1094 if ( sizeof(ob_name) > 11 && ob_name[0..11] == "/std/shells/" )
1095 ob_name = ob_name[11..];
1096
1097 ob_name = ob_name + ":" + loginname;
1098
1099 if ( old_ob = find_object(ob_name) ){
1100 catch( old_ob->remove(); publish );
1101
1102 if ( old_ob )
1103 destruct( old_ob );
1104 }
1105
1106 rename_object( ob, ob_name );
1107 ob->__reload_explore();
1108 ob->set_realip(realip);
1109 ob->start_player(cap_name);
1110 ob->SetProp( "creation_date", creation_date );
1111 ob->Set( "creation_date", SAVE|SECURED|PROTECTED, F_MODE_AS );
1112
1113 ob->move( "/room/nowhere", M_NOCHECK );
1114 set_object_heart_beat( ob, 0 );
1115 destruct( this_object() );
1116
1117 return ob;
1118}
1119
1120string query_realip()
1121{
1122 return realip ? realip : "";
1123}
1124
1125int query_invis()
1126{
1127 return invis;
1128}
1129