/** Can a player control a thing? * The control rules are, in order: * Only God controls God. * Wizards control everything else. * Nothing else controls a wizard, and only royalty control royalty. * Mistrusted objects control only themselves. * Objects with the same owner control each other, unless the * target object is TRUST and the would-be controller isn't. * If ZMOs allow control, and you pass the ZMO, you control. * If the owner is a Zone Master, and you pass the ZM, you control. * If you pass the control lock, you control. * Otherwise, no dice. * \param who object attempting to control. * \param what object to be controlled. * \retval 1 who controls what. * \retval 0 who doesn't control what. */ int controls(dbref who, dbref what) { boolexp c; if (!GoodObject(what)) return 0; if (Guest(who)) return 0; if (what == who) return 1; if (God(what)) return 0; if (Wizard(who)) return 1; if (Wizard(what) || (Hasprivs(what) && !Hasprivs(who))) return 0; if (Mistrust(who)) return 0; if (Owns(who, what) && (!Inheritable(what) || Inheritable(who))) return 1; if (Inheritable(what) || IsPlayer(what)) return 0; if (!ZONE_CONTROL_ZMP && (Zone(what) != NOTHING) && eval_lock(who, Zone(what), Zone_Lock)) return 1; if (ZMaster(Owner(what)) && !IsPlayer(what) && eval_lock(who, Owner(what), Zone_Lock)) return 1; c = getlock_noparent(what, Control_Lock); if (c != TRUE_BOOLEXP) { if (eval_boolexp(who, c, what, NULL)) return 1; } return 0; }
/** Decide if a host can access someway. * \param hname a host or user+host pattern. * \param flag the access type we're testing. * \param who the player attempting access. * \retval 1 access permitted. * \retval 0 access denied. * \verbatim * Given a hostname and a flag decide if the host can do it. * Here's how it works: * We run the linked list and take the first match. * (If the hostname is user@host, we try to match both user@host * and just host to each line in the file.) * If we make a match, and the line tells us whether the site can/can't * do the action, we're done. * Otherwise, we assume that the host can do any toggleable option * (can create, connect, guest), and don't have any special * flags (can't register, isn't suspect) * \endverbatim */ bool site_can_access(const char *hname, uint32_t flag, dbref who) { struct access *ap; acsflag *c; const char *p; if (!hname || !*hname) return 0; if ((p = strchr(hname, '@'))) p++; for (ap = access_top; ap; ap = ap->next) { if (ap->can & ACS_SITELOCK) continue; if ((ap->can & ACS_REGEXP) ? (qcomp_regexp_match(ap->re, hname) || (p && qcomp_regexp_match(ap->re, p))) : (quick_wild(ap->host, hname) || (p && quick_wild(ap->host, p))) && (ap->who == AMBIGUOUS || ap->who == who)) { /* Got one */ if (flag & ACS_CONNECT) { if ((ap->cant & ACS_GOD) && God(who)) /* God can't connect from here */ return 0; else if ((ap->cant & ACS_WIZARD) && Wizard(who)) /* Wiz can't connect from here */ return 0; else if ((ap->cant & ACS_ADMIN) && Hasprivs(who)) /* Wiz and roy can't connect from here */ return 0; } if (ap->cant && ((ap->cant & flag) == flag)) return 0; if (ap->can && (ap->can & flag)) return 1; /* Hmm. We don't know if we can or not, so continue */ break; } } /* Flag was neither set nor unset. If the flag was a toggle, * then the host can do it. If not, the host can't */ for (c = acslist; c->name; c++) { if (flag & c->flag) return c->toggle ? 1 : 0; } /* Should never reach here, but just in case */ return 1; }
/** Change an object's zone. * \verbatim * This implements @chzone. * \endverbatim * \param player the enactor. * \param name name of the object to change zone of. * \param newobj name of new ZMO. * \param noisy if 1, notify player about success and failure. * \param preserve was the /preserve switch given? * \param pe_info the pe_info for lock and permission checks * \retval 0 failed to change zone. * \retval 1 successfully changed zone. */ int do_chzone(dbref player, char const *name, char const *newobj, bool noisy, bool preserve, NEW_PE_INFO *pe_info) { dbref thing; dbref zone; int has_lock; if ((thing = noisy_match_result(player, name, NOTYPE, MAT_NEARBY)) == NOTHING) return 0; if (!newobj || !*newobj || !strcasecmp(newobj, "none")) zone = NOTHING; else { if ((zone = noisy_match_result(player, newobj, NOTYPE, MAT_EVERYTHING)) == NOTHING) return 0; } if (Zone(thing) == zone) { if (noisy) notify(player, T("That object is already in that zone.")); return 0; } if (!controls(player, thing)) { if (noisy) notify(player, T("You don't have the power to shift reality.")); return 0; } /* a player may change an object's zone to: * 1. NOTHING * 2. an object he controls * 3. an object with a chzone-lock that the player passes. * Note that an object with no chzone-lock isn't valid */ has_lock = (getlock(zone, Chzone_Lock) != TRUE_BOOLEXP); if (!(Wizard(player) || (zone == NOTHING) || controls(player, zone) || (has_lock && eval_lock_with(player, zone, Chzone_Lock, pe_info)))) { if (noisy) { if (has_lock) { fail_lock(player, zone, Chzone_Lock, T("You cannot move that object to that zone."), NOTHING); } else { notify(player, T("You cannot move that object to that zone.")); } } return 0; } /* Don't chzone object to itself for mortals! */ if ((zone == thing) && !Hasprivs(player)) { if (noisy) notify(player, T("You shouldn't zone objects to themselves!")); return 0; } /* Don't allow circular zones */ if (GoodObject(zone)) { dbref tmp; int zone_depth = MAX_ZONES; for (tmp = Zone(zone); GoodObject(tmp); tmp = Zone(tmp)) { if (tmp == thing) { notify(player, T("You can't make circular zones!")); return 0; } if (tmp == Zone(tmp)) /* Ran into an object zoned to itself */ break; zone_depth--; if (!zone_depth) { notify(player, T("Overly deep zone chain.")); return 0; } } } /* Don't allow chzone to objects without elocks! * If no lock is set, set a default lock (warn if zmo are used for control) * This checks for many trivial elocks (canuse/1, where &canuse=1) */ if (zone != NOTHING) check_zone_lock(player, zone, noisy); /* Warn Wiz/Royals when they zone their stuff */ if ((zone != NOTHING) && Hasprivs(Owner(thing))) { if (noisy) notify(player, T("Warning: @chzoning admin-owned object!")); } /* everything is okay, do the change */ Zone(thing) = zone; /* If we're not unzoning, and we're working with a non-player object, * we'll remove wizard, royalty, inherit, and powers, for security, unless * a wizard is changing the zone and explicitly says not to. */ if (!Wizard(player)) preserve = 0; if (!preserve && ((zone != NOTHING) && !IsPlayer(thing))) { /* if the object is a player, resetting these flags is rather * inconvenient -- although this may pose a bit of a security * risk. Be careful when @chzone'ing wizard or royal players. */ clear_flag_internal(thing, "WIZARD"); clear_flag_internal(thing, "ROYALTY"); clear_flag_internal(thing, "TRUST"); destroy_flag_bitmask("POWER", Powers(thing)); Powers(thing) = new_flag_bitmask("POWER"); } else { if (noisy && (zone != NOTHING)) { if (Hasprivs(thing)) notify(player, T("Warning: @chzoning a privileged player.")); if (Inherit(thing)) notify(player, T("Warning: @chzoning a TRUST player.")); } } if (noisy) notify(player, T("Zone changed.")); return 1; }
/** Change an object's owner. * \verbatim * This implements @chown. * \endverbatim * \param player the enactor. * \param name name of object to change owner of. * \param newobj name of new owner for object. * \param preserve if 1, preserve privileges and don't halt the object. * \param pe_info the pe_info for lock checks */ void do_chown(dbref player, const char *name, const char *newobj, int preserve, NEW_PE_INFO *pe_info) { dbref thing; dbref newowner = NOTHING; long match_flags = MAT_POSSESSION | MAT_HERE | MAT_EXIT | MAT_ABSOLUTE; /* check for '@chown <object>/<atr>=<player>' */ if (strchr(name, '/')) { do_atrchown(player, name, newobj); return; } if (Wizard(player)) match_flags |= MAT_PLAYER; if ((thing = noisy_match_result(player, name, TYPE_THING, match_flags)) == NOTHING) return; if (!*newobj || !strcasecmp(newobj, "me")) { newowner = player; } else { if ((newowner = lookup_player(newobj)) == NOTHING) { notify(player, T("I couldn't find that player.")); return; } } if (IsPlayer(thing) && !God(player)) { notify(player, T("Players always own themselves.")); return; } /* Permissions checking */ if (!chown_ok(player, thing, newowner, pe_info)) { notify(player, T("Permission denied.")); return; } if (IsThing(thing) && !Hasprivs(player) && !(GoodObject(Location(thing)) && (Location(thing) == player))) { notify(player, T("You must carry the object to @chown it.")); return; } if (preserve && !Wizard(player)) { notify(player, T("You cannot @CHOWN/PRESERVE. Use normal @CHOWN.")); return; } /* chowns to the zone master don't count towards fees */ if (!ZMaster(newowner)) { /* Debit the owner-to-be */ if (!can_pay_fees(newowner, Pennies(thing))) { /* not enough money or quota */ if (newowner != player) notify(player, T ("That player doesn't have enough money or quota to receive that object.")); return; } /* Credit the current owner */ giveto(Owner(thing), Pennies(thing)); change_quota(Owner(thing), QUOTA_COST); } chown_object(player, thing, newowner, preserve); notify(player, T("Owner changed.")); }