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