/* Add a new, or restrict an existing, standard attribute from cnf file */ int cnf_attribute_access(char *attrname, char *opts) { ATTR *a; privbits flags = 0; upcasestr(attrname); if (!good_atr_name(attrname)) return 0; if (strcasecmp(opts, "none")) { flags = list_to_privs(attr_privs_set, opts, 0); if (!flags) return 0; } a = (ATTR *) ptab_find_exact(&ptab_attrib, attrname); if (a) { if (AF_Internal(a)) return 0; } else { a = (ATTR *) mush_malloc(sizeof(ATTR), "ATTR"); if (!a) return 0; AL_NAME(a) = strdup(attrname); a->data = NULL_CHUNK_REFERENCE; ptab_insert_one(&ptab_attrib, attrname, a); } AL_FLAGS(a) = flags; AL_CREATOR(a) = GOD; return 1; }
/** Add a new attribute. Called from db.c to add new attributes * to older databases which have their own attr table. * \param name name of attr to add * \param flags attribute flags (AF_*) */ void add_new_attr(char *name, uint32_t flags) { ATTR *ap; ap = (ATTR *) ptab_find_exact(&ptab_attrib, name); if (ap || !good_atr_name(name)) return; ap = (ATTR *) mush_malloc(sizeof(ATTR), "ATTR"); if (!ap) { do_log(LT_ERR, 0, 0, "add_new_attr: unable to malloc ATTR"); return; } AL_NAME(ap) = strdup(name); ap->data = NULL_CHUNK_REFERENCE; AL_FLAGS(ap) = flags; AL_CREATOR(ap) = 0; ptab_insert_one(&ptab_attrib, name, ap); }
/** Rename an attribute in the attribute table. * \verbatim * Top-level function for @attrib/rename. * \endverbatim * \param player the enactor. * \param old the name of the attribute to rename. * \param newname the new name (surprise!) */ void do_attribute_rename(dbref player, char *old, char *newname) { ATTR *ap; if (!old || !*old || !newname || !*newname) { notify(player, T("Which attributes do you mean?")); return; } upcasestr(old); upcasestr(newname); /* Is the new name valid? */ if (!good_atr_name(newname)) { notify(player, T("Invalid attribute name.")); return; } /* Is the new name already in use? */ ap = (ATTR *) ptab_find_exact(&ptab_attrib, newname); if (ap) { notify_format(player, T("The name %s is already used in the attribute table."), newname); return; } /* Is the old name a real attribute? */ ap = (ATTR *) ptab_find_exact(&ptab_attrib, old); if (!ap) { notify(player, T("That attribute isn't in the attribute table")); return; } /* Ok, take it out and put it back under the new name */ ptab_delete(&ptab_attrib, old); /* This causes a slight memory leak if you rename an attribute added via /access. But that doesn't happen often. Will fix someday. */ AL_NAME(ap) = strdup(newname); ptab_insert_one(&ptab_attrib, newname, ap); notify_format(player, T("Renamed %s to %s in attribute table."), old, newname); return; }
/** Check to see that the lock type is a valid type. * If it's not in our lock table, it's not valid, * unless it begins with 'user:'******'t allow '|' in lock names because it * will confuse our db-reading routines. * * Might destructively modify name. * * \param player the enactor, for notification. * \param thing object on which to check the lock. * \param name name of lock type. * \return lock type, or NULL. */ static lock_type check_lock_type(dbref player, dbref thing, lock_type name) { lock_type ll; char *sp; /* Special-case for basic locks. */ if (!name || !*name) return Basic_Lock; /* Normal locks. */ ll = match_lock(name); if (ll != NULL) return ll; /* If the lock is set, it's allowed, whether it exists normally or not. */ if (getlock(thing, name) != TRUE_BOOLEXP) return name; /* Check to see if it's a well-formed user-defined lock. */ sp = strchr(name, ':'); if (!sp) { notify(player, T("Unknown lock type.")); return NULL; } *sp++ = '\0'; if (!string_prefix("User", name)) { notify(player, T("Unknown lock type.")); return NULL; } if (strchr(sp, '|')) { notify(player, T("The character \'|\' may not be used in lock names.")); return NULL; } if (!good_atr_name(sp)) { notify(player, T("That is not a valid lock name.")); return NULL; } return sp; }
/** Check to see that the lock type is a valid type. * If it's not in our lock table, it's not valid, * unless it begins with 'user:'******'t allow '|' in lock names because it * will confuse our db-reading routines. * * * \param player the enactor, for notification. * \param thing object on which to check the lock. * \param name name of lock type. * \return lock type, or NULL. */ static lock_type check_lock_type(dbref player, dbref thing, lock_type name) { lock_type ll; char user_name[BUFFER_LEN]; char *colon; /* Special-case for basic locks. */ if (!name || !*name) return Basic_Lock; /* Normal locks. */ ll = match_lock(name); if (ll != NULL) return ll; /* If the lock is set, it's allowed, whether it exists normally or not. */ if (getlock(thing, name) != TRUE_BOOLEXP) return name; /* Check to see if it's a well-formed user-defined lock. */ if (!string_prefix(name, "User:"******"Unknown lock type.")); return NULL; } if (strchr(name, '|')) { notify(player, T("The character \'|\' may not be used in lock names.")); return NULL; } colon = strchr(name, ':') + 1; mush_strncpy(user_name, colon, BUFFER_LEN); if (!good_atr_name(user_name)) { notify(player, T("That is not a valid lock name.")); return NULL; } return colon; }
/** 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)); }
void attr_read_all(PENNFILE *f) { ATTR *a; int c, found, count = 0; char alias[BUFFER_LEN]; /* Clear existing attributes */ ptab_free(&ptab_attrib); ptab_start_inserts(&ptab_attrib); db_read_this_labeled_int(f, "attrcount", &count); for (found = 0;;) { c = penn_fgetc(f); penn_ungetc(c, f); if (c != ' ') break; found++; if ((a = attr_read(f))) ptab_insert(&ptab_attrib, a->name, a); } ptab_end_inserts(&ptab_attrib); if (found != count) do_rawlog(LT_ERR, "WARNING: Actual number of attrs (%d) different than expected count (%d).", found, count); /* Assumes we'll always have at least one alias */ db_read_this_labeled_int(f, "attraliascount", &count); for (found = 0;;) { c = penn_fgetc(f); penn_ungetc(c, f); if (c != ' ') break; found++; if ((a = attr_alias_read(f, alias))) { upcasestr(alias); if (!good_atr_name(alias)) { do_rawlog(LT_ERR, "Bad attribute name on alias '%s' in db.", alias); } else if (aname_find_exact(strupper(alias))) { do_rawlog(LT_ERR, "Unable to alias attribute '%s' to '%s' in db: alias already in use.", AL_NAME(a), alias); } else if (!alias_attribute(AL_NAME(a), alias)) { do_rawlog(LT_ERR, "Unable to alias attribute '%s' to '%s' in db.", AL_NAME(a), alias); } } } if (found != count) do_rawlog(LT_ERR, "WARNING: Actual number of attr aliases (%d) different than expected count (%d).", found, count); return; }
static ATTR * attr_read(PENNFILE *f) { ATTR *a; char *tmp; dbref d = GOD; privbits flags = 0; a = (ATTR *) mush_malloc(sizeof(ATTR), "ATTR"); if (!a) { mush_panic("Not enough memory to add attribute in attr_read()!"); return NULL; } AL_NAME(a) = NULL; a->data = NULL_CHUNK_REFERENCE; AL_FLAGS(a) = 0; AL_CREATOR(a) = GOD; a->next = NULL; db_read_this_labeled_string(f, "name", &tmp); if (!good_atr_name(tmp)) { do_rawlog(LT_ERR, "Invalid attribute name '%s' in db.", tmp); (void) getstring_noalloc(f); /* flags */ (void) getstring_noalloc(f); /* creator */ (void) getstring_noalloc(f); /* data */ free_standard_attr(a, 0); return NULL; } AL_NAME(a) = strdup(tmp); db_read_this_labeled_string(f, "flags", &tmp); if (tmp && *tmp && strcasecmp(tmp, "none")) { flags = list_to_privs(attr_privs_db, tmp, 0); if (!flags) { do_rawlog(LT_ERR, "Invalid attribute flags for '%s' in db.", AL_NAME(a)); free((char *) AL_NAME(a)); (void) getstring_noalloc(f); /* creator */ (void) getstring_noalloc(f); /* data */ free_standard_attr(a, 0); return NULL; } } AL_FLAGS(a) = flags; db_read_this_labeled_dbref(f, "creator", &d); AL_CREATOR(a) = d; db_read_this_labeled_string(f, "data", &tmp); if (!tmp || !*tmp || !(AL_FLAGS(a) & (AF_ENUM | AF_RLIMIT))) { a->data = NULL_CHUNK_REFERENCE; } else if (AL_FLAGS(a) & AF_ENUM) { /* Store string as it is */ char *t = compress(tmp); a->data = chunk_create(t, strlen(t), 0); free(t); } else if (AL_FLAGS(a) & AF_RLIMIT) { /* Need to validate regexp */ char *t; pcre *re; const char *errptr; int erroffset; re = pcre_compile(tmp, PCRE_CASELESS, &errptr, &erroffset, tables); if (!re) { do_rawlog(LT_ERR, "Invalid regexp in limit for attribute '%s' in db.", AL_NAME(a)); free_standard_attr(a, 0); return NULL; } pcre_free(re); /* don't need it, just needed to check it */ t = compress(tmp); a->data = chunk_create(t, strlen(t), 0); free(t); } return a; }