/* -*- LPC -*- */ /* * $Locker: $ * $Id: base_master.c,v 1.17 2003/04/15 23:52:04 pinkfish Exp $ * $Log: base_master.c,v $ * Revision 1.17 2003/04/15 23:52:04 pinkfish * Fix up the assignment stuff anfd add in the ability to set a directory * assigned to no one. * * Revision 1.16 2003/03/05 22:40:59 pinkfish * Fix up an error which caused the size of the array to get over keen. * * Revision 1.15 2003/03/05 22:30:32 pinkfish * Make the lord default to the top of the domain. * * Revision 1.14 2003/03/04 22:57:33 pinkfish * Fix it up to remove things correctly. * * Revision 1.13 2003/03/04 22:47:21 pinkfish * Fix up the assignment stuff. * * Revision 1.12 2003/03/04 22:38:45 pinkfish * Make it do directory assignment stuff. * * Revision 1.11 2002/03/01 15:14:24 taffyd * Fixed a STUPID mistake. * * Revision 1.10 2002/02/24 17:02:47 taffyd * Added set_idle_mess() and query_idle_mess() for use in /secure/finger. * * Revision 1.9 2002/02/24 06:20:05 taffyd * Added better rcsforce allowed code * * Revision 1.8 2001/11/05 06:33:46 drakkos * Added support for $project$ codes in creator projects to query the project tracker for project info. * * Revision 1.7 2001/09/08 00:23:13 ceres * Mofified to let HLs change stuff * * Revision 1.6 2001/08/14 14:36:48 drakkos * Added a base query_changelog() method. * * Revision 1.5 2001/04/05 21:00:25 pinkfish * Add in allowing deputies to rcsforce. * * Revision 1.4 2001/02/27 23:54:22 pinkfish * Fix up the copy() around the deputies. * * Revision 1.3 2001/02/27 23:53:27 ceres * Forcibly unlocked by pinkfish * * Revision 1.2 1999/10/04 23:31:22 turrican * Fixed permission checking function * * Revision 1.1 1998/01/06 04:03:45 ceres * Initial revision * */ /* * This file is inherited by the domain master objects. */ #include <project_management.h> #include <player_handler.h> #include <error_handler.h> #define LOCK_MASK 8 #define PROJECT_CODE "$project$" mapping members; mapping access; nosave private mapping _project_cache; private int _use_tracker; private string _idle_mess; string *deputies; private mapping _directory_assignments; private mapping _rcsforce_allowed; string query_lord(); int query_use_tracker(); void set_use_tracker(int); string query_domain() { string *words; if (!file_name (this_object())) { return ""; } words = explode (file_name(this_object()), "/"); if (sizeof (words) < 2) { return ""; } return words[1]; } int query_prevent_shadow() { return 1; } /* query_prevent_shadow() */ protected void create() { members = ([ ]); access = ([ ]); deputies = ({ }); _project_cache = ([ ]); _rcsforce_allowed = ([ ]); _idle_mess = 0; unguarded((: restore_object, file_name(this_object()) :)); if (!deputies) { deputies = ({ }); } if (!_directory_assignments) { _directory_assignments = ([ ]); } if ( !_rcsforce_allowed ) { _rcsforce_allowed = ([ ]); } } /* create() */ void save_me() { unguarded((: save_object, file_name(this_object()) :)); } /* save_me() */ int add_permission(string euid, string path, int mask) { if (previous_object() != master()) { return 0; } if (!access[path]){ access[path] = ([ euid : mask ]); } else { access[path][euid] |= mask; } save_me(); return 1; } /* add_permission() */ int remove_permission(string euid, string path, int mask) { if (previous_object() != master()) return 0; if (!access[path]) return 0; if (!access[path][euid]) return 0; access[path][euid] &= ~mask; if (!access[path][euid]) map_delete(access[path], euid); if (!sizeof(access[path])) map_delete(access, path); save_me(); return 1; } /* remove_permission() */ int check_permission(string euid, string *path, int mask) { string p; mapping perms; if ((sizeof(path) >= 3) && (path[2] == "master.c" || path[2] == "master.o" || path[2] == "master")) return 0; p = "/" + implode(path, "/"); perms = master()->permission_match_path(access, p); if (!perms || !sizeof(perms)) { return 0; } if (perms[euid] && ((perms[euid] & mask) || (perms["all"] & mask))) { return 1; } if (perms["all"] & LOCK_MASK) { return -1; } return 0; } /* check_permission() */ int valid_read(string, string euid, string) { /* * Default is to allow reading for everyone. */ return 1; /* Use this if you only want your domain members to be able to read in the * the domain. */ return (members[euid] != 0); } /* valid_read() */ int valid_write(string *path, string euid, string) { /* * Default is to deny write access for everyone, except the lord * and independent creators. */ return 0; /* * Blue... Use this if you want all your creators to have * write access everywhere in the domain. */ if ((sizeof(path) >= 3) && (path[2] == "master.c" || path[2] == "master.o" || path[2] == "master")) return 0; return (members[euid] != 0); } /* valid_write() */ void dest_me() { destruct(this_object()); } /* dest_me() */ int check_call_tree(int only_lord) { object *obs; int found; int i; obs = previous_object(-1); for (i = 0; i < sizeof(obs); i++) { /* Look for all the creator/lord objects */ if (file_name(obs[i])[0..12] == "/global/lord#" || (file_name(obs[i])[0..15] == "/global/creator#")) { if("/secure/master"->query_administrator(obs[i]->query_name()) || obs[i]->query_name() == query_lord() || (!only_lord && (member_array(obs[i]->query_name(), deputies) != -1))) { found = 1; } else { return 0; } } } return found; } /* check_call_tree() */ int add_member(string name) { if (!check_call_tree(0)) { return 0; } if (members[name]) return 0; members[name] = "newbie"; save_me(); return 1; } /* add_member() */ int remove_member(string name) { int pos; /* Only the lord can delete deputies... */ if (!check_call_tree(member_array(name, deputies) != -1)) { return 0; } if (!members[name]) return 0; members = m_delete(members, name); pos = member_array(name, deputies); if (pos != -1) { deputies = deputies[0..pos - 1] + deputies[pos + 1..]; } save_me(); return 1; } /* remove_member() */ int add_deputy(string name) { if (!check_call_tree(1)) { return 0; } if (!members[name]) return 0; if (!deputies) deputies = ({ }); if (member_array(name, deputies) != -1) return 1; deputies += ({ name }); save_me(); return 1; } /* add_deputy() */ int remove_deputy(string name) { int pos; if (!check_call_tree(1)) { return 0; } if (!deputies) deputies = ({ }); pos = member_array(name, deputies); if (pos == -1) return 0; deputies = deputies[0..pos - 1] + deputies[pos + 1..]; save_me(); return 1; } /* remove_deputy() */ int add_rcsforce_allowed( string creator, string directory ) { if (!check_call_tree(1)) { return 0; } if ( _rcsforce_allowed[ creator ] ) { _rcsforce_allowed[ creator ] += ({ directory }); } else { _rcsforce_allowed[ creator ] = ({ directory }); } save_me(); return 1; } /* add_rcsforce_allowed() */ int remove_rcsforce_allowed( string creator, string directory ) { if (!check_call_tree(1)) { return 0; } if ( _rcsforce_allowed[ creator ] ) { _rcsforce_allowed[ creator ] -= ({ directory }); if ( sizeof( _rcsforce_allowed ) == 0 ) { map_delete( _rcsforce_allowed, creator ); } save_me(); } return 1; } /* remove_rcsforce_allowed() */ string *query_members() { return keys(members); } /* query_members() */ int set_project(string name, string pro) { if (!check_call_tree(0)) { return 0; } if (!members[name]) return 0; if (!pro || pro == "") pro = "project unset"; members[name] = pro; save_me(); return 1; } /* set_project() */ string query_project(string name) { string *proj; string project; project = members[name]; // Check to see if they have a project set. if (!project) { // Nope. Return project unset. return "project unset"; } // Check to see if the string $project$ appears // anywhere in the string. If it does, we will // replace this string with the project information // from the tracker. if (strsrch (project, PROJECT_CODE) != -1) { // No sizeof the cache... so let's initialise it. if (!sizeof (_project_cache)) { _project_cache = ([ ]); } if (undefinedp (_project_cache[name])) { // We haven't already queried the manager for this // creator, so we'd better do that. We cache what we get // back so that we don't continually hammer the CPU every // time. proj = PROJECT_HANDLER->query_projects_for_creator_in_domain (name, query_domain()); if (sizeof (proj)) { // There were projects returned by the tracker, so // let's make the project cache equal a q_m_s string // of the projects. _project_cache[name] = query_multiple_short (proj); } else { // Nothing is stored for this creator, so we'll // simply replace $project$ with the currently set // project. _project_cache[name] = members[name]; } } // Now, return the proper project code. return replace (project, ({PROJECT_CODE, _project_cache[name]})); } else { return members[name]; } } /* query_project() */ int query_deputy(string name) { if (!deputies) return 0; if (member_array(name, deputies) != -1) return 1; return 0; } /* query_deputy() */ string *query_deputies() { return copy(deputies); } mapping query_access() { return copy(access); } /* query_access() */ string query_lord() { return "Something is broken"; } /* query_lord() */ /** * Called to check for rcsforcing of a file. By default we allow the deputies * to rcsforce things. * @param file the file to check * @param person the person forcing * @param locker the person who has the lock */ int can_rcsforce(string file, string person, string locker) { string *directories; string fdir; if (query_deputy(person)) { return 1; } directories = _rcsforce_allowed[ person ]; if ( directories ) { fdir = file[ 0..strsrch( file, "/", -1 ) -1 ]; foreach ( string directory in directories ) { if ( fdir[ 0.. sizeof( directory ) - 1 ] == directory ) { return 1; } } } return 0; } /* can_rcsforce() */ string query_changelog (string filename) { return "/d/" + query_domain() + "/ChangeLog"; } void set_use_tracker(int i) { _use_tracker = i; } int query_use_tracker() { return _use_tracker; } int nuke_creator_project_cache(string *creators) { if (!_project_cache) { return 0; } foreach (string c in creators) { map_delete (_project_cache, c); return 1; } } int set_idle_mess( string txt ) { if (!check_call_tree(1)) { return 0; } _idle_mess = txt; save_me(); return 1; } /* set_idle_mess() */ string query_idle_mess() { return _idle_mess; } /* query_idle_mess() */ /** * Finds the person assigned to the specific directory. It will climb * up the directory tree looking for who to assign the directory too. * @param dir the directory to find assignments in * @return the array of people assigned to the directory */ string* query_assigned_to_directory(string* dir) { string str; int i; i = sizeof(dir) - 1; do { str = "/" + implode(dir[0..<i], "/"); i--; } while (i >= 0 && !_directory_assignments[str]); if (_directory_assignments[str]) { return _directory_assignments[str]; } // Make the default the lord return ({ query_lord() }); } /** * This method allows a specific person to be assigned to the given * directory. * @param dir the directory to assign someone too * @param people the people who are assigned to the directory */ int assign_people_to_directory(string dir, string* people) { if (previous_object() != master()) { return 0; } if (sizeof(people)) { if (sizeof(people) == 1 && people[0] == ERROR_ASSIGNED_NO_ONE) { people = ({ }); } _directory_assignments[dir] = people; } else { map_delete(_directory_assignments, dir); } save_me(); return 1; } /** * This method returns all the current assignments from directory to the * people who are looking after them. * @return the directory assignment mapping */ mapping query_directory_assignments() { mapping ret; string dir; ret = copy(_directory_assignments); dir = "/d/" + query_domain(); if (!ret[dir]) { ret[dir] = ({ query_lord() }); } else { ret[dir] |= ({ query_lord() }); } return ret; }