/** Is a alias a valid player alias-list for thing? * It must be a semicolon-separated list of valid player names * with no more than than MAX_ALIASES names, if the player isn't * a wizard. * \param alias list to check. * \param player player for permission checks. * \param thing player who is being aliased. * \return One of the OPAE_* constants defined in hdrs/attrib.h */ enum opa_error ok_player_alias(const char *alias, dbref player, dbref thing) { char tbuf1[BUFFER_LEN], *s, *sp; int cnt = 0; if (!alias || !*alias) return OPAE_NULL; strncpy(tbuf1, alias, BUFFER_LEN - 1); tbuf1[BUFFER_LEN - 1] = '\0'; s = trim_space_sep(tbuf1, ALIAS_DELIMITER); while (s) { sp = split_token(&s, ALIAS_DELIMITER); while (sp && *sp && *sp == ' ') sp++; if (!sp || !*sp) return OPAE_NULL; /* No null aliases */ if (!ok_player_name(sp, player, thing)) return OPAE_INVALID; cnt++; } if (Wizard(player)) return OPAE_SUCCESS; if (cnt > MAX_ALIASES) return OPAE_TOOMANY; return OPAE_SUCCESS; }
int set_alias(dbref target, const char *alias, int rotate) { PData pdat; const char *p = alias; /* is the new alias legal? */ while (*p && *p != ':' && *p != PROPDIR_DELIMITER) p++; if (*p || !ok_player_name(alias)) { return NOTHING; } /* is the new alias actually available? */ if (lookup_alias(alias, 0) != NOTHING) { return AMBIGUOUS; } /* set the new alias */ sprintf(abuf, ALIASDIR_CUR "%s", alias); pdat.flags = PROP_REFTYP; pdat.data.ref = target; set_property(0, abuf, &pdat); if (rotate) { rotate_alias(target, 0); /* set the "last alias" hint */ sprintf(abuf, ALIASDIR_LAST "%d", (int) target); add_property(0, abuf, alias, 0); } return 0; }
/** Attempt to create a new player object. * \param d DESC the creation attempt is being made on (if from connect screen) * \param executor dbref of the object attempting to create a player (if * \@pcreate) * \param name name of player to create. * \param password initial password of created player. * \param host host from which creation is attempted. * \param ip ip address from which creation is attempted. * \return dbref of created player, NOTHING if invalid name, AMBIGUOUS if taken * name, or HOME for a bad password * password. */ dbref create_player(DESC *d, dbref executor, const char *name, const char *password, const char *host, const char *ip) { if (!ok_player_name(name, executor, NOTHING)) { do_log(LT_CONN, 0, 0, "Failed creation (bad name) from %s", host); if (d) { queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s", d->descriptor, ip, mark_failed(ip), "create: bad name", name); } return (lookup_player(name) == NOTHING ? NOTHING : AMBIGUOUS); } if (!ok_password(password)) { do_log(LT_CONN, 0, 0, "Failed creation (bad password) from %s", host); if (d) { queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s", d->descriptor, ip, mark_failed(ip), "create: bad password", name); } return HOME; } if (DBTOP_MAX && (db_top >= DBTOP_MAX + 1) && (first_free == NOTHING)) { /* Oops, out of db space! */ do_log(LT_CONN, 0, 0, "Failed creation (no db space) from %s", host); if (d) { queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s", d->descriptor, ip, mark_failed(ip), "create: no db space left to create!", name); } return NOTHING; } /* else he doesn't already exist, create him */ return make_player(name, password, host, ip); }
dbref create_player(const char *name, const char *password) { dbref player; if (!ok_player_name(name) || !ok_password(password)) return NOTHING; /* else he doesn't already exist, create him */ player = new_object(); /* initialize everything */ NAME(player) = alloc_string(name); DBFETCH(player)->location = tp_player_start; /* home */ FLAGS(player) = TYPE_PLAYER | PCREATE_FLAGS; OWNER(player) = player; DBFETCH(player)->sp.player.home = tp_player_start; DBFETCH(player)->exits = NOTHING; DBFETCH(player)->sp.player.pennies = tp_start_pennies; DBFETCH(player)->sp.player.password = NULL; // handle this last DBFETCH(player)->sp.player.curr_prog = NOTHING; DBFETCH(player)->sp.player.insert_mode = 0; /* link him to tp_player_start */ PUSH(player, DBFETCH(tp_player_start)->contents); add_player(player); DBDIRTY(player); DBDIRTY(tp_player_start); set_password(player, password); return player; }
void prim_pname_okp(PRIM_PROTOTYPE) { CHECKOP(1); oper1 = POP(); if (oper1->type != PROG_STRING) abort_interp("Player name string expected."); if (!oper1->data.string) abort_interp("Cannot be an empty string."); result = ok_player_name(oper1->data.string->data); CLEAR(oper1); PushInt(result); }
dbref create_player(const char *name, const char *password) { char buf[80]; dbref player; if (!ok_player_name(name) || !ok_password(password)) return NOTHING; if (!tp_building || tp_db_readonly) return NOTHING; /* else he doesn't already exist, create him */ player = new_object(); /* initialize everything */ NAME(player) = alloc_string(name); FLAGS(player) = TYPE_PLAYER | PCREATE_FLAGS; FLAG2(player) = PCREATE_FLAG2; DBFETCH(player)->location = RootRoom; /* home */ OWNER(player) = player; DBFETCH(player)->sp.player.home = RootRoom; DBFETCH(player)->exits = NOTHING; DBFETCH(player)->sp.player.pennies = tp_start_pennies; DBFETCH(player)->sp.player.password = alloc_string(password); DBFETCH(player)->sp.player.curr_prog = NOTHING; DBFETCH(player)->sp.player.insert_mode = 0; /* link him to tp_player_start */ PUSH(player, DBFETCH(RootRoom)->contents); add_player(player); DBDIRTY(player); DBDIRTY(RootRoom); sprintf(buf, CNOTE "%s is born!", PNAME(player)); anotify_except(DBFETCH(RootRoom)->contents, NOTHING, buf, player); return player; }
/** Is name a valid new name for thing, when set by player? * \verbatim * Parses names and aliases for players/exits, validating each. If everything is valid, * the new name and alias are set into newname and newalias, with memory malloc'd as necessary. * For things/rooms, no parsing is done, and ok_name is called on the entire string to validate. * For players and exits, if name takes the format <name>; then newname is set to <name> and * newalias to ";", to signify that the existing alias should be cleared. If name contains a name and * valid aliases, newname and newalias are set accordingly. * \endverbatim * \param name the new name to set * \param player the player setting the name, for permission checks * \param thing object getting the name, or NOTHING for new objects * \param type type of object getting the name (necessary for new exits) * \param newname pointer to place the new name, once validated * \param newalias pointer to place the alias in, if any * \retval OPAE_SUCCESS name and any given aliases are valid * \retval OPAE_INVALID invalid name or aliases * \retval OPAE_TOOMANY too many aliases for player */ enum opa_error ok_object_name(char *name, dbref player, dbref thing, int type, char **newname, char **newalias) { char *bon, *eon; char nbuff[BUFFER_LEN], abuff[BUFFER_LEN]; char *ap = abuff; int aliases = 0; int empty = 0; strncpy(nbuff, name, BUFFER_LEN - 1); nbuff[BUFFER_LEN - 1] = '\0'; memset(abuff, 0, BUFFER_LEN); /* First, check for a quoted player name */ if (type == TYPE_PLAYER && *name == '"') { /* Quoted player name, no aliases allowed */ bon = nbuff; bon++; eon = bon; while (*eon && *eon != '"') eon++; if (*eon) *eon = '\0'; if (!ok_player_name(bon, player, thing)) return OPAE_INVALID; *newname = mush_strdup(bon, "name.newname"); return OPAE_SUCCESS; } if (type & (TYPE_THING | TYPE_ROOM)) { /* No aliases in the name */ if (!ok_name(nbuff, 0)) return OPAE_INVALID; *newname = mush_strdup(nbuff, "name.newname"); return OPAE_SUCCESS; } /* A player or exit name, with aliases allowed. * Possible things to parse: * <name> - just a new name * <name>; - new name with trailing ; to clear alias * <name>;<alias1>[;<aliasN>] - name with one or more aliases, separated by ; */ /* Validate name first */ bon = nbuff; if ((eon = strchr(bon, ALIAS_DELIMITER))) { *eon++ = '\0'; aliases++; } if (! (type == TYPE_PLAYER ? ok_player_name(bon, player, thing) : ok_name(bon, 1))) return OPAE_INVALID; *newname = mush_strdup(bon, "name.newname"); if (aliases) { /* We had aliases, so parse them */ while (eon) { if (empty) return OPAE_NULL; /* Null alias only valid as a single, final alias */ bon = eon; if ((eon = strchr(bon, ALIAS_DELIMITER))) { *eon++ = '\0'; } while (*bon && *bon == ' ') bon++; if (!*bon) { empty = 1; /* empty alias, should only happen if we have no proper aliases */ continue; } if (! (type == TYPE_PLAYER ? ok_player_name(bon, player, thing) : ok_name(bon, 1))) { *newalias = mush_strdup(bon, "name.newname"); /* So we can report the invalid alias */ return OPAE_INVALID; } if (aliases > 1) { safe_chr(ALIAS_DELIMITER, abuff, &ap); } safe_str(bon, abuff, &ap); aliases++; } } *ap = '\0'; if (aliases) { if (!Wizard(player) && type == TYPE_PLAYER && aliases > MAX_ALIASES) return OPAE_TOOMANY; if (*abuff) { /* We have actual aliases */ *newalias = mush_strdup(abuff, "name.newname"); } else { ap = abuff; safe_chr(ALIAS_DELIMITER, abuff, &ap); *ap = '\0'; /* We just want to clear the existing alias */ *newalias = mush_strdup(abuff, "name.newname"); } } return OPAE_SUCCESS; }
dbref create_player(dbref creator, const char *name, const char *password) { char buf[BUFFER_LEN]; struct object *newp; dbref player; if (!ok_player_name(name) || !ok_password(password) || tp_db_readonly) return NOTHING; /* remove any existing alias with this name */ clear_alias(0, name); /* else he doesn't already exist, create him */ player = new_object(creator); newp = DBFETCH(player); /* initialize everything */ NAME(player) = alloc_string(name); FLAGS(player) = TYPE_PLAYER; if (OkObj(tp_player_prototype) && (Typeof(tp_player_prototype) == TYPE_PLAYER)) { FLAGS(player) = FLAGS(tp_player_prototype); FLAG2(player) = FLAG2(tp_player_prototype); if (tp_pcreate_copy_props) { newp->properties = copy_prop(tp_player_prototype); #ifdef DISKBASE newp->propsfpos = 0; newp->propsmode = PROPS_UNLOADED; newp->propstime = 0; newp->nextold = NOTHING; newp->prevold = NOTHING; dirtyprops(player); #endif } } if (OkObj(tp_player_start)) { DBFETCH(player)->location = tp_player_start; DBFETCH(player)->sp.player.home = tp_player_start; } else { DBFETCH(player)->location = GLOBAL_ENVIRONMENT; DBFETCH(player)->sp.player.home = GLOBAL_ENVIRONMENT; } OWNER(player) = player; newp->exits = NOTHING; newp->sp.player.pennies = tp_start_pennies; newp->sp.player.password = NULL; /* this has to stay here. -hinoserm */ newp->sp.player.curr_prog = NOTHING; newp->sp.player.insert_mode = 0; #ifdef IGNORE_SUPPORT newp->sp.player.ignoretime = 0; #endif /* IGNORE_SUPPORT */ /* set password */ set_password(player, password); /* link him to tp_player_start */ PUSH(player, DBFETCH(tp_player_start)->contents); add_player(player); DBDIRTY(player); DBDIRTY(tp_player_start); sprintf(buf, CNOTE "%s is born!", NAME(player)); anotify_except(DBFETCH(tp_player_start)->contents, NOTHING, buf, player); return player; }
/** Attempt to register a new player at the connect screen. * If registration is allowed, a new player object is created with * a random password which is emailed to the registering player. * \param name name of player to register. * \param email email address to send registration details. * \param host host from which registration is being attempted. * \param ip ip address from which registration is being attempted. * \return dbref of created player or NOTHING if creation failed. */ dbref email_register_player(DESC *d, const char *name, const char *email, const char *host, const char *ip) { char *p; char passwd[20]; static char elems[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; int i, len; bool resend = 0; dbref player = NOTHING; FILE *fp; size_t NELEMS = sizeof(elems) - 1; char sbuff[260]; if (!check_fails(ip)) { return NOTHING; } if (strlen(options.sendmail_prog) == 0) return NOTHING; if (!ok_player_name(name, NOTHING, NOTHING)) { /* Check for re-registration request */ player = lookup_player(name); if (GoodObject(player)) { ATTR *a; a = atr_get(player, "LASTLOGOUT"); if (!a) { a = atr_get(player, "REGISTERED_EMAIL"); if (a && !strcasecmp(atr_value(a), email)) resend = 1; } } if (!resend) { do_log(LT_CONN, 0, 0, "Failed registration (bad name) from %s", host); queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s", d->descriptor, ip, mark_failed(ip), "register: bad name", name); return NOTHING; } } if (!resend) { /* Make sure that the email address is kind of valid. A valid * address must contain a @. Let the mailer sort it out beyond * that. 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 ((p = strrchr(email, '@'))) { p++; if (!Site_Can_Register(p)) { if (!Deny_Silent_Site(p, AMBIGUOUS)) { do_log(LT_CONN, 0, 0, "Failed registration (bad site in email: %s) from %s", email, host); queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s", d->descriptor, ip, mark_failed(ip), "register: bad site in email", name); } return NOTHING; } } else { if (!Deny_Silent_Site(host, AMBIGUOUS)) { do_log(LT_CONN, 0, 0, "Failed registration (bad email: %s) from %s", email, host); queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s", d->descriptor, ip, mark_failed(ip), "register: sitelocked host", name); } return NOTHING; } if (DBTOP_MAX && (db_top >= DBTOP_MAX + 1) && (first_free == NOTHING)) { /* Oops, out of db space! */ do_log(LT_CONN, 0, 0, "Failed registration (no db space) from %s", host); queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s", d->descriptor, ip, count_failed(ip), "register: no db space left to create!", name); return NOTHING; } } /* Come up with a random password of length 7-12 chars */ len = get_random_u32(7, 12); for (i = 0; i < len; i++) passwd[i] = elems[get_random_u32(0, NELEMS - 1)]; 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. * 2) We'll cross our fingers and hope nobody uses this to spam. */ release_fd(); snprintf(sbuff, sizeof sbuff, "%s -t", options.sendmail_prog); if ((fp = popen(sbuff, "w")) == NULL) { do_log(LT_CONN, 0, 0, "Failed registration of %s by %s: unable to open sendmail", name, email); queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s,%d", d->descriptor, ip, count_failed(ip), "register: Unable to open sendmail!", name, 1); reserve_fd(); return NOTHING; } fprintf(fp, "Subject: "); fprintf(fp, T("[%s] Registration of %s\n"), MUDNAME, name); fprintf(fp, "To: %s\n", email); fprintf(fp, "Precedence: junk\n"); fprintf(fp, "\n"); fprintf(fp, T("This is an automated message.\n")); fprintf(fp, "\n"); fprintf(fp, T("Your requested player, %s, has been created.\n"), name); fprintf(fp, T("The password is %s\n"), passwd); fprintf(fp, "\n"); fprintf(fp, T("To access this character, connect to %s and type:\n"), MUDNAME); fprintf(fp, "\tconnect \"%s\" %s\n", name, passwd); fprintf(fp, "\n"); i = pclose(fp); reserve_fd(); if (i != 0) { /* Mailer exited with an error code. Log it. */ do_rawlog( LT_CONN, "When attempting to email a password to a newly registered player,\n" "\tthe mailer exited with error code %d.\n" "\t(Check /usr/include/sysexits.h if present for the meaning.)", i); queue_event(SYSEVENT, "SOCKET`CREATEFAIL", "%d,%s,%d,%s,%s,%d", d->descriptor, ip, count_failed(ip), "register: Unable to send email", name, i); return NOTHING; } else if (resend) { /* Reset the password */ (void) atr_add(player, pword_attr, password_hash(passwd, NULL), GOD, 0); return player; } else { /* Ok, all's well, make a player */ player = make_player(name, passwd, host, ip); queue_event(SYSEVENT, "PLAYER`CREATE", "%s,%s,%s,%d,%s", unparse_objid(player), name, "register", d->descriptor, email); (void) atr_add(player, "REGISTERED_EMAIL", email, GOD, 0); return player; } }