/* player.c */ #include "copyrite.h" #include "config.h" #include <stdio.h> #ifdef I_UNISTD #include <unistd.h> #endif #ifdef I_STRING #include <string.h> #else #include <strings.h> #endif #ifdef I_SYS_TIME #include <sys/time.h> #else #include <time.h> #endif #ifdef I_SYS_TYPES #include <sys/types.h> #endif #include <fcntl.h> #include "conf.h" #include "mushdb.h" #include "intrface.h" #include "externs.h" #include "access.h" #include "confmagic.h" extern time_t mudtime; extern int reserved; extern void add_player _((dbref player, char *alias)); int password_check _((dbref player, const char *password)); dbref connect_player _((const char *name, const char *password, const char *host)); dbref create_player _((const char *name, const char *password, const char *host)); dbref email_register_player _((const char *name, const char *email, const char *host)); static dbref make_player _((const char *name, const char *password, const char *host)); void do_password _((dbref player, const char *old, const char *newobj)); void check_last _((dbref player, const char *host)); void check_lastfailed _((dbref player, const char *host)); int password_check(player, password) dbref player; const char *password; { ATTR *a; /* read the password and compare it */ if ((a = atr_get_noparent(player, "XYXXY")) && strcmp(uncompress(a->value), password) && strcmp(mush_crypt(password), uncompress(a->value))) return 0; #if (CRYPT_SYSTEM > 0) /* prevent direct entry of the raw encrypted password */ if ((strlen(password) == 13) && (password[0] == 'X') && (password[1] == 'X')) return 0; #endif /* we're okay */ return 1; } dbref connect_player(name, password, host) const char *name; const char *password; const char *host; { dbref player; dbref i; /* validate name */ if ((player = lookup_player(name)) == NOTHING) return NOTHING; /* See if player is allowed to connect like this */ if (Guest(player) && !Site_Can_Guest(host)) { do_log(LT_CONN, 0, 0, "Connection to %s (GUEST) not allowed from %s", name, host); return NOTHING; } else if (!Guest(player) && !Site_Can_Connect(host)) { do_log(LT_CONN, 0, 0, "Connection to %s (Non-GUEST) not allowed from %s", name, host); return NOTHING; } /* validate password */ if (!Guest(player)) if (!password_check(player, password)) { #ifdef CREATION_TIMES /* Increment count of login failures */ ModTime(player)++; #endif check_lastfailed(player, host); return NOTHING; } /* If it's a Guest player, and already connected, search the * db for another Guest player to connect them to. */ if (Guest(player) && Connected(player)) { /* Search db for an unconnected Guest */ for (i = 0; i < db_top; i++) { if ((Typeof(i) == TYPE_PLAYER) && !Hasprivs(i) && Guest(i) && !Connected(i)) { player = i; break; } } if (i == db_top) { /* We failed to find an unconnected Guest */ do_log(LT_CONN, 0, 0, "Multiple connection to Guest #%d", player); } } if (Suspect_Site(host)) { do_log(LT_CONN, 0, 0, "Connection from Suspect site. Setting %s(#%d) suspect.", Name(player), player); Toggles(player) |= PLAYER_SUSPECT; } return player; } /* This function returns NOTHING if the player name was bad, and * AMBIGUOUS if the player password was bad */ dbref create_player(name, password, host) const char *name; const char *password; const char *host; { if (!ok_player_name(name)) { do_log(LT_CONN, 0, 0, "Failed creation (bad name) from %s", host); return NOTHING; } if (!ok_password(password)) { do_log(LT_CONN, 0, 0, "Failed creation (bad password) from %s", host); return AMBIGUOUS; } /* else he doesn't already exist, create him */ return make_player(name, password, host); } /* The HAS_SENDMAIL ifdef is kept here as a hint to metaconfig */ #ifdef MAILER #undef HAS_SENDMAIL #define HAS_SENDMAIL 1 #undef SENDMAIL #define SENDMAIL MAILER #endif #ifdef HAS_SENDMAIL dbref email_register_player(name, email, host) const char *name; const char *email; const char *host; { char *p; char passwd[BUFFER_LEN]; static char elems[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; int i, len; dbref player; FILE *fp; if (!ok_player_name(name)) { do_log(LT_CONN, 0, 0, "Failed registration (bad name) from %s", host); return NOTHING; } /* Make sure that the email address is valid. A valid address must * contain either an @ or a ! * Also, to prevent someone from using the MUSH to mailbomb another site, * let's make sure that the site to which the user wants the email * sent is also allowed to use the register command. * If there's an @, we check whatever's after the last @ * (since @foo.bar:user@host is a valid email) * If not, we check whatever comes before the first ! */ if ((p = strrchr(email, '@'))) { p++; if (!Site_Can_Register(p)) { do_log(LT_CONN, 0, 0, "Failed registration (bad site in email: %s) from %s", email, host); return NOTHING; } } else if ((p = strchr(email, '!'))) { *p = '\0'; if (!Site_Can_Register(email)) { *p = '!'; do_log(LT_CONN, 0, 0, "Failed registration (bad site in email: %s) from %s", email, host); return NOTHING; } else *p = '!'; } else { do_log(LT_CONN, 0, 0, "Failed registration (bad email: %s) from %s", email, host); return NOTHING; } /* Come up with a random password of length 7-12 chars */ len = 7 + getrandom(6); for (i = 0; i < len; i++) passwd[i] = elems[getrandom(strlen(elems))]; passwd[len] = '\0'; /* If we've made it here, we can send the email and create the * character. Email first, since that's more likely to go bad. * Some security precautions we'll take: * 1) We'll use sendmail -t, so we don't pass user-given values to a shell. */ #ifndef WIN32 close(reserved); #endif if ((fp = popen(tprintf("%s -t", SENDMAIL), "w")) == NULL) { do_log(LT_CONN, 0, 0, "Failed registration of %s by %s: unable to open sendmail", name, email); #ifndef WIN32 reserved = open("/dev/null", O_RDWR); #endif return NOTHING; } fprintf(fp, "Subject: [%s] Registration of %s\n", MUDNAME, name); fprintf(fp, "To: %s\n", email); fprintf(fp, "Precedence: junk\n"); fprintf(fp, "\n"); fprintf(fp, "This is an automated message.\n"); fprintf(fp, "\n"); fprintf(fp, "Your requested player, %s, has been created.\n", name); fprintf(fp, "The password is %s\n", passwd); fprintf(fp, "\n"); fprintf(fp, "To access this character, connect to %s and type:\n", MUDNAME); fprintf(fp, "\tconnect %s %s\n", name, passwd); fprintf(fp, "\n"); pclose(fp); #ifndef WIN32 reserved = open("/dev/null", O_RDWR); #endif /* Ok, all's well, make a player */ player = make_player(name, passwd, host); (void) atr_add(player, "REGISTERED_EMAIL", email, GOD, NOTHING); return player; } #else dbref email_register_player(name, email, host) const char *name; const char *email; const char *host; { do_log(LT_CONN, 0, 0, "Failed registration (no sendmail) from %s", host); return NOTHING; } #endif static dbref make_player(name, password, host) const char *name; const char *password; const char *host; { dbref player; char *s; #ifdef QUOTA char temp[SBUF_LEN]; #endif /* else he doesn't already exist, create him */ s = ctime(&mudtime); s[strlen(s) - 1] = '\0'; if (s[8] == ' ') s[8] = '0'; player = new_object(); /* initialize everything */ SET(Name(player), name); Location(player) = PLAYER_START; Home(player) = PLAYER_START; Owner(player) = player; db[player].parent = NOTHING; Flags(player) = TYPE_PLAYER; Flags(player) |= options.player_flags; Toggles(player) |= options.player_toggles; if (Suspect_Site(host)) Toggles(player) |= PLAYER_SUSPECT; #ifdef USE_WARNINGS set_initial_warnings(player); #endif #ifdef CREATION_TIMES /* Modtime tracks login failures */ ModTime(player) = (time_t) 0; #endif atr_add(player, "XYXXY", mush_crypt(password), GOD, NOTHING); giveto(player, START_BONUS); /* starting bonus */ (void) atr_add(player, "LAST", s, GOD, NOTHING); (void) atr_add(player, "LASTSITE", host, GOD, NOTHING); (void) atr_add(player, "LASTFAILED", " ", GOD, NOTHING); #ifdef QUOTA sprintf(temp, "%d", START_QUOTA); (void) atr_add(player, "RQUOTA", temp, GOD, NOTHING); #endif /* QUOTA */ #ifdef FIXED_FLAG #ifndef EMPTY_ATTRS (void) atr_add(player, "ICLOC", " ", GOD, AF_MDARK | AF_PRIVATE | AF_WIZARD | AF_NOCOPY); #else (void) atr_add(player, "ICLOC", "", GOD, AF_MDARK | AF_PRIVATE | AF_WIZARD | AF_NOCOPY); #endif #endif #ifdef USE_MAILER (void) atr_add(player, "MAILCURF", "0", GOD, AF_LOCKED | AF_NOPROG | AF_WIZARD); add_folder_name(player, 0, "inbox"); #endif /* link him to PLAYER_START */ PUSH(player, db[PLAYER_START].contents); add_player(player, NULL); add_lock(player, Basic_Lock, parse_boolexp(player, "=me")); add_lock(player, Enter_Lock, parse_boolexp(player, "=me")); #ifdef LOCAL_DATA local_data_create(player); #endif return player; } void do_password(player, old, newobj) dbref player; const char *old; const char *newobj; { if (Guest(player)) { notify(player, "Guests may not change their passwords."); return; } if (!password_check(player, old)) { notify(player, "Sorry"); } else if (!ok_password(newobj)) { notify(player, "Bad new password."); } else { atr_add(player, "XYXXY", mush_crypt(newobj), GOD, NOTHING); notify(player, "Password changed."); } } void check_last(player, host) dbref player; const char *host; { char *s; ATTR *a; ATTR *h; char last_time[MAX_COMMAND_LEN / 8]; char last_place[MAX_COMMAND_LEN]; s = ctime(&mudtime); s[strlen(s) - 1] = 0; /* compare to last connect see if player gets salary */ a = atr_get_noparent(player, "LAST"); if (a && (strncmp(uncompress(a->value), s, 10) != 0)) giveto(player, PAY_CHECK); /* tell the player where he last connected from */ h = atr_get_noparent(player, "LASTSITE"); if (h && a) { strcpy(last_place, uncompress(h->value)); strcpy(last_time, uncompress(a->value)); notify(player, tprintf("Last connect was from %s on %s.", last_place, last_time)); } /* How about last failed connection */ h = atr_get_noparent(player, "LASTFAILED"); if (h && a) { strcpy(last_place, uncompress(h->value)); if (strlen(last_place) > 2) notify(player, tprintf("Last FAILED connect was from %s.", last_place)); } /* if there is no Lastsite, then the player is newly created. * the extra variables are a kludge to work around some weird * behavior involving uncompress. */ /* set the new attributes */ (void) atr_add(player, "LAST", s, GOD, NOTHING); (void) atr_add(player, "LASTSITE", host, GOD, NOTHING); (void) atr_add(player, "LASTFAILED", " ", GOD, NOTHING); } /* This is called on a failed connection */ void check_lastfailed(player, host) dbref player; const char *host; { char *s; char last_place[MAX_COMMAND_LEN]; s = ctime(&mudtime); s[strlen(s) - 1] = 0; sprintf(last_place, "%s on %s", host, s); (void) atr_add(player, "LASTFAILED", last_place, GOD, NOTHING); }