/** Check for CHARGES on thing and, if present, lower. * \param thing object being used. * \retval 0 charges was set to 0 * \retval 1 charges not set, or was > 0 */ int charge_action(dbref thing) { ATTR *b; char tbuf2[BUFFER_LEN]; int num; /* check if object has # of charges */ b = atr_get_noparent(thing, "CHARGES"); if (!b) { return 1; /* no CHARGES */ } else { strcpy(tbuf2, atr_value(b)); num = atoi(tbuf2); if (num > 0) { /* charges left, decrement and execute */ (void) atr_add(thing, "CHARGES", tprintf("%d", num - 1), Owner(b->creator), 0); return 1; } else { /* no charges left, try to execute runout */ return 0; } } }
/** Retrieve the amount of quote remaining to a player. * Figure out a player's quota. Add the RQUOTA attribute if he doesn't * have one already. This function returns the REMAINING quota, not * the TOTAL limit. * \param who player to check. * \return player's remaining quota. */ int get_current_quota(dbref who) { ATTR *a; int i; int limit; int owned = 0; /* if he's got an RQUOTA attribute, his remaining quota is that */ a = atr_get_noparent(Owner(who), "RQUOTA"); if (a) return parse_integer(atr_value(a)); /* else, count up his objects. If he has less than the START_QUOTA, * then his remaining quota is that minus his number of current objects. * Otherwise, it's his current number of objects. Add the attribute * if he doesn't have it. */ for (i = 0; i < db_top; i++) if (Owner(i) == Owner(who)) owned++; owned--; /* don't count the player himself */ if (owned <= START_QUOTA) limit = START_QUOTA - owned; else limit = owned; (void) atr_add(Owner(who), "RQUOTA", tprintf("%d", limit), GOD, 0); return limit; }
/** Processing related to players' last connections. * Here we check to see if a player gets a paycheck, tell them their * last connection site, and update all their LAST* attributes. * \param player dbref of player. * \param host hostname of player's current connection. * \param ip ip address of player's current connection. */ void check_last(dbref player, const char *host, const char *ip) { char *s; ATTR *a; ATTR *h; char last_time[MAX_COMMAND_LEN / 8]; char last_place[MAX_COMMAND_LEN]; /* compare to last connect see if player gets salary */ s = show_time(mudtime, 0); a = atr_get_noparent(player, "LAST"); if (a && (strncmp(atr_value(a), s, 10) != 0)) giveto(player, Paycheck(player)); /* tell the player where he last connected from */ if (!Guest(player)) { h = atr_get_noparent(player, "LASTSITE"); if (h && a) { strcpy(last_place, atr_value(h)); strcpy(last_time, atr_value(a)); notify_format(player, T("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, atr_value(h)); if (strlen(last_place) > 2) notify_format(player, T("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, 0); (void) atr_add(player, "LASTSITE", host, GOD, 0); (void) atr_add(player, "LASTIP", ip, GOD, 0); (void) atr_add(player, "LASTFAILED", " ", GOD, 0); }
/** Check a player's password against a given string. * * First checks new-style formatted password strings * If that doesn't match, tries old-style SHA0 password * strings, and upgrades the stored password. * If that doesn't match, tries really-old-style crypt(3) * password strings, and upgrades the stored password. * If that doesn't work, you lose. * * \param player dbref of player. * \param password plaintext password string to check. * \retval 1 password matches (or player has no password). * \retval 0 password fails to match. */ bool password_check(dbref player, const char *password) { ATTR *a; char *saved; /* read the password and compare it */ if (!(a = atr_get_noparent(player, pword_attr))) return 1; /* No password attribute */ saved = strdup(atr_value(a)); if (!saved) return 0; if (!password_comp(saved, password)) { /* Nope. Try SHA0. */ char *passwd = mush_crypt_sha0(password); if (strcmp(saved, passwd) != 0) { /* Not SHA0 either. Try old-school crypt(); */ #ifdef HAVE_CRYPT if (strcmp(crypt(password, "XX"), saved) != 0) { /* Nope */ #endif /* HAVE_CRYPT */ /* See if it's a MUX password */ if (!check_mux_password(saved, password)) { /* As long as it's not obviously encrypted, check for a * plaintext password. */ if (strlen(password) < 4 || *password == '$' || (password[0] == 'X' && password[1] == 'X') || strcmp(saved, password)) { free(saved); return 0; } } #ifdef HAVE_CRYPT } #endif } /* Something worked. Change password to SHS-encrypted */ do_rawlog(LT_CONN, "Updating password format for player #%d", player); (void) atr_add(player, pword_attr, password_hash(password, NULL), GOD, 0); } /* Success! */ free(saved); return 1; }
/** Reset all of a player's player list entries (names/aliases). * This is called when a player changes name or alias. * We remove all their old entries, and add back their new ones. * \param player dbref of player * \param oldname player's former name (NULL if not changing) * \param oldalias player's former aliases (NULL if not changing) * \param name player's new name * \param alias player's new aliases */ void reset_player_list(dbref player, const char *oldname, const char *oldalias, const char *name, const char *alias) { char tbuf1[BUFFER_LEN]; char tbuf2[BUFFER_LEN]; if (!oldname) name = Name(player); if (oldalias) { mush_strncpy(tbuf1, oldalias, BUFFER_LEN); if (alias) { strncpy(tbuf2, alias, BUFFER_LEN - 1); tbuf2[BUFFER_LEN - 1] = '\0'; } else { tbuf2[0] = '\0'; } } else { /* We are not changing aliases, just name, but we need to get the * aliases anyway, since we may change name to something that's * in the alias, and thus must not be deleted. */ ATTR *a = atr_get_noparent(player, "ALIAS"); if (a) { mush_strncpy(tbuf1, atr_value(a), BUFFER_LEN); } else { tbuf1[0] = '\0'; } strcpy(tbuf2, tbuf1); } /* Delete all the old stuff */ delete_player(player, tbuf1); delete_player(player, NULL); /* Add in the new stuff */ add_player_alias(player, name); add_player_alias(player, tbuf2); }
/** Clone an object. * \verbatim * This is the top-level function for @clone, which creates a duplicate * of a (non-player) object. * \endverbatim * \param player the enactor. * \param name the name of the object to clone. * \param newname the name to give the duplicate. * \param preserve if 1, preserve ownership and privileges on duplicate. * \param newdbref the (unparsed) dbref to give the object, or NULL to use the next free * \param pe_info The pe_info to use for lock and \@command priv checks * \return dbref of the duplicate, or NOTHING. */ dbref do_clone(dbref player, char *name, char *newname, int preserve, char *newdbref, NEW_PE_INFO *pe_info) { dbref clone, thing; char dbnum[BUFFER_LEN]; thing = noisy_match_result(player, name, NOTYPE, MAT_EVERYTHING); if (thing == NOTHING) return NOTHING; if (newname && *newname && !ok_name(newname, IsExit(thing))) { notify(player, T("That is not a reasonable name.")); return NOTHING; } if (!controls(player, thing) || IsPlayer(thing) || (IsRoom(thing) && !command_check_byname(player, "@dig", pe_info)) || (IsExit(thing) && !command_check_byname(player, "@open", pe_info)) || (IsThing(thing) && !command_check_byname(player, "@create", pe_info))) { notify(player, T("Permission denied.")); return NOTHING; } /* don't allow cloning of destructed things */ if (IsGarbage(thing)) { notify(player, T("There's nothing left of it to clone!")); return NOTHING; } if (preserve && !Wizard(player)) { notify(player, T("You cannot @CLONE/PRESERVE. Use normal @CLONE instead.")); return NOTHING; } if (!make_first_free_wrapper(player, newdbref)) { return NOTHING; } /* make sure owner can afford it */ switch (Typeof(thing)) { case TYPE_THING: if (can_pay_fees(player, Pennies(thing))) { clone = clone_object(player, thing, newname, preserve); notify_format(player, T("Cloned: Object %s."), unparse_dbref(clone)); if (IsRoom(player)) moveto(clone, player, player, "cloned"); else moveto(clone, Location(player), player, "cloned"); current_state.things++; local_data_clone(clone, thing, preserve); real_did_it(player, clone, NULL, NULL, NULL, NULL, "ACLONE", NOTHING, NULL, 0, 0); return clone; } return NOTHING; break; case TYPE_ROOM: if (can_pay_fees(player, ROOM_COST)) { clone = clone_object(player, thing, newname, preserve); Exits(clone) = NOTHING; notify_format(player, T("Cloned: Room #%d."), clone); current_state.rooms++; local_data_clone(clone, thing, preserve); real_did_it(player, clone, NULL, NULL, NULL, NULL, "ACLONE", NOTHING, NULL, 0, 0); return clone; } return NOTHING; break; case TYPE_EXIT: /* For exits, we don't want people to be able to link it to a location they can't with @open. So, all this stuff. */ switch (Location(thing)) { case NOTHING: strcpy(dbnum, "#-1"); break; case HOME: strcpy(dbnum, "home"); break; case AMBIGUOUS: strcpy(dbnum, "variable"); break; default: strcpy(dbnum, unparse_dbref(Location(thing))); } if (newname && *newname) clone = do_real_open(player, newname, dbnum, NOTHING, pe_info); else clone = do_real_open(player, Name(thing), dbnum, NOTHING, pe_info); if (!GoodObject(clone)) { return NOTHING; } else { char *alias_val = NULL; ATTR *alias_attr = NULL; alias_attr = atr_get_noparent(clone, "ALIAS"); if (alias_attr) { alias_val = safe_atr_value(alias_attr, "atrval.do_clone"); atr_clr(clone, "ALIAS", GOD); } atr_cpy(clone, thing); if (alias_val) { atr_add(clone, "ALIAS", alias_val, player, 0); mush_free(alias_val, "atrval.do_clone"); } clone_locks(player, thing, clone); Zone(clone) = Zone(thing); Parent(clone) = Parent(thing); Flags(clone) = clone_flag_bitmask("FLAG", Flags(thing)); if (!preserve) { clear_flag_internal(clone, "WIZARD"); clear_flag_internal(clone, "ROYALTY"); Warnings(clone) = 0; /* zap warnings */ Powers(clone) = new_flag_bitmask("POWER"); /* zap powers */ } else { Warnings(clone) = Warnings(thing); Powers(clone) = clone_flag_bitmask("POWER", Powers(thing)); } if (Wizard(clone) || Royalty(clone) || Warnings(clone) || !null_flagmask("POWER", Powers(clone))) notify(player, T ("Warning: @CLONE/PRESERVE on an object with WIZ, ROY, @powers, or @warnings.")); notify_format(player, T("Cloned: Exit #%d."), clone); local_data_clone(clone, thing, preserve); return clone; } } return NOTHING; }
/** Add new standard attributes, or change permissions on them. * \verbatim * Given the name and permission string for an attribute, add it to * the attribute table (or modify the permissions if it's already * there). Permissions may be changed retroactively, which modifies * permissions on any copies of that attribute set on objects in the * database. This is the top-level code for @attribute/access. * \endverbatim * \param player the enactor. * \param name the attribute name. * \param perms a string of attribute permissions, space-separated. * \param retroactive if true, apply the permissions retroactively. */ void do_attribute_access(dbref player, char *name, char *perms, int retroactive) { ATTR *ap, *ap2; privbits flags = 0; int i; int insert = 0; /* Parse name and perms */ if (!name || !*name) { notify(player, T("Which attribute do you mean?")); return; } if (strcasecmp(perms, "none")) { flags = list_to_privs(attr_privs_set, perms, 0); if (!flags) { notify(player, T("I don't understand those permissions.")); return; } } upcasestr(name); /* Is this attribute already in the table? */ ap = (ATTR *) ptab_find_exact(&ptab_attrib, name); if (ap) { if (AF_Internal(ap)) { /* Don't muck with internal attributes */ notify(player, T("That attribute's permissions can not be changed.")); return; } } else { /* Create fresh if the name is ok */ if (!good_atr_name(name)) { notify(player, T("Invalid attribute name.")); return; } insert = 1; ap = (ATTR *) mush_malloc(sizeof(ATTR), "ATTR"); if (!ap) { notify(player, T("Critical memory failure - Alert God!")); do_log(LT_ERR, 0, 0, "do_attribute_access: unable to malloc ATTR"); return; } AL_NAME(ap) = strdup(name); ap->data = NULL_CHUNK_REFERENCE; } AL_FLAGS(ap) = flags; AL_CREATOR(ap) = player; /* Only insert when it's not already in the table */ if (insert) { ptab_insert_one(&ptab_attrib, name, ap); } /* Ok, now we need to see if there are any attributes of this name * set on objects in the db. If so, and if we're retroactive, set * perms/creator */ if (retroactive) { for (i = 0; i < db_top; i++) { if ((ap2 = atr_get_noparent(i, name))) { if (AL_FLAGS(ap2) & AF_ROOT) AL_FLAGS(ap2) = flags | AF_ROOT; else AL_FLAGS(ap2) = flags; AL_CREATOR(ap2) = player; } } } notify_format(player, T("%s -- Attribute permissions now: %s"), name, privs_to_string(attr_privs_view, flags)); }