// File : /cmds/std/_su.c // Creator : Sulam@TMI (1-21-92) // Updated : Huma@TMI (11-15-92) for conversion to mudlib 0.9 // // Completely overhauled by Watcher@TMI (2-18-93) for new connection // login system, and to improve a few of the su processes. // // Updated by Watcher@TMI (03/92) to accomodated body transfers // into monsters by users. // // Updated by Watcher@TMI (04/04/93) stripping away multiple user // capabilities to avoid confusion and fix a few other things. // // This command allows wizards to refresh their player object, or // change into another user, if the correct password is known. // Admins are not required to enter the password. #include <uid.h> #include <priv.h> #include <config.h> #include <logs.h> #include <mudlib.h> #include <daemons.h> #include <channels.h> #include <login.h> #include <login_macros.h> inherit DAEMON ; // Local hack? #undef CAP_NAME #ifndef CAP_NAME_MASTER_ONLY #define CAP_NAME(ob) capitalize((ob)->query("name")) #else #define CAP_NAME(ob) (ob)->query("name") #endif mapping active = ([]); static int link_monster(string name); static int get_password(string pass); static void enter_world(); static int check_password(string pass); static void try_again(); static void switch_player(); static void complete_entry(string str); void create() { seteuid(getuid(this_object())); // Set daemons permissions } int cmd_su(string name) { object ob; // Setup the euid of the command to ROOT seteuid( getuid(this_object()) ); // If no name is given assume user's real (non-monster) name if(!name) name = (string)this_player()->link_data("name"); // Make sure user's name is lowercase name = lower_case(name); // Check to see if anyone is using the su command. if(!undefinedp(active["new"])) { notify_fail("Su: The su command is presently in use. Please try again.\n"); return 0; } // Check to see if a monster matches the requested id if(wizardp(this_player()) && link_monster(name)) return 1; // Create new connection object to link ob = new(CONNECTION); // Check to see if user actually exists in the database if(!file_exists(user_data_file(ob, name) + __SAVE_EXTENSION__)) { if(wizardp(this_player())) write("Su: No such user or monster exists.\n"); else write("Su: No such user exists.\n"); ob->remove(); return 1; } // Add user and connection object to su storage array active["old"] = this_player(); active["new"] = ob; active["who"] = name; // Set and pass permissions seteuid( name ); export_uid(ob); seteuid(getuid()); // Name connection object and attempt to restore user's data ob->SET_NAME(name); if(!ob->restore()) { write("Su: Could not restore requested user.\n"); ob->remove(); active = ([]); return 1; } if(!wizardp(this_player()) && !ob->query("wizard") && name != (string)this_player()->link_data("name")) { write("Su: Players may only su to themselves or a wizard character.\n"); ob->remove(); active = ([]); return 1; } // If user is an admin, and target isn't an admin if(adminp(this_player()->link_data("name")) && !adminp(name)) { active["same"] = 0; switch_player(); } // Switching to a new user ... ask for password else if((string)this_player()->link_data("name") != name) { active["same"] = 0; input_to("get_password", 1); write("Password: "); } // Same player ... so don't ask password else { active["same"] = 1; switch_player(); } return 1; } static int get_password(string pass) { write("\n"); // Check to see if inputed password is correct if(!check_password(pass)) { write("Su: Incorrect password.\n"); active = ([]); return 0; } // If correct, change into the new shell switch_player(); return 1; } static int check_password(string pass) { string password; // Get stored character password from connection object password = (string)active["new"]->PASS; // Compared inputed password with stored character password if(password != crypt(pass, password)) return 0; return 1; } static void switch_player() { int volume, capacity; // Switch interactive between old and new shells /* if(member_array("/std/body.c",deep_inherit_list(active["new"])) == -1){ write("Security violation\n"); return 1; } */ if( exec(active["new"], active["old"]) ) enter_world(); else { write("Su: Login attempt failed.\n"); active["new"]->remove(); active = ([]); return; } } static void enter_world() { object *inv; string *history; int cmd_num, ptr, max; int i, volume, capacity; // Save present user configuration active["old"]->save_data(); // Setup new user object and move inventory to new host if(!active["new"]->restore_body() || !active["new"]->connect() || !active["new"]->BODY_OB->query("name")) { write("Su: Could not restore new user body.\n"); exec(active["old"], active["new"]); active["new"]->BODY_OB->remove(); active["new"]->remove(); active = ([]); return; } // Get old user volume and capacity if(active["same"]) { volume = (int)active["old"]->query("volume"); capacity = (int)active["old"]->query("capacity"); } history = copy((string *)active["old"]->query_history()); cmd_num = (int)active["old"]->query_cmd_num(); max = (int)active["old"]->query_max(); ptr = (int)active["old"]->query_ptr(); // Move the inventory..etc.. if old isn't a monster. if(!active["old"]->query("npc") && !active["new"]->query("npc")) { for(inv=all_inventory(active["old"]); i<sizeof(inv); i++) if(!inv[i]->query_auto_load()) inv[i]->move( active["new"]->BODY_OB ); // Reset previous volume and capacity in new user shell // in users last, so the move always succeeds if(active["same"]) { active["new"]->set("volume", volume); active["new"]->set("capacity", capacity); } } #ifdef SU_LOG log_file(SU_LOG, CAP_NAME(active["old"]) + ": sued into " + CAP_NAME(active["new"]) + " from " + query_ip_name(this_player()) + " [" + extract(ctime(time()), 4, 15) + "]\n"); #endif if(active["old"]->query("npc")) { write("Reappear in the same location? [y/n] "); input_to("complete_entry", 0); return; } complete_entry("yes"); return; } static void complete_entry(string str) { string domain; if(!str || member_array(str, ({ "y", "yes", "n", "no" })) == -1) { write("Reappear in the same location? [y/n] "); input_to("complete_entry", 0); return; } if(str == "no" || str == "n") active["new"]->BODY_OB->move( START ); else active["new"]->BODY_OB->move( environment(active["old"]) ); if(active["old"]->query("npc")) { active["old"]->clear_monster(); domain = master()->domain_file(file_name(active["old"])); switch (domain) { case ROOT_UID: case BACKBONE_UID: case "NONAME": case "User": case "Anonymous": seteuid("Anonymous"); break; default: seteuid(domain); break; } export_uid(active["old"]); seteuid(getuid()); active["old"]->reset_monster(); } if(active["same"]) { write("Transfer complete.\n"); if(!active["old"]->query("npc")) message("prompt", this_player()->write_prompt(1), this_player()); active["new"]->BODY_OB->init_setup(); } else { write("You polymorph into " + active["new"]->query("cap_name") + ".\n"); say(active["old"]->query("cap_name") + " polymorphed into " + active["new"]->query("cap_name") + ".\n", ({ active["old"], active["new"] })); active["new"]->BODY_OB->init_setup(); } // Announce the departure of the old char if different from new if(!active["same"] && !active["old"]->query("npc")) ANNOUNCE->announce_user( active["old"], 1 ); if(!active["old"]->query("npc")) { active["old"]->save_data(); active["old"]->remove(); } CHANNELS_D -> initialize_user(); active = ([]); } // This function handles the user transfers into monster shells static int link_monster(string name) { object ob, old; int ret; old = this_player(); ob = get_object( name ); // Check to see if a monster matches the requested id if(!ob || !ob->query("npc") || !environment(ob) || this_player() == ob) return 0; if(interactive(ob)) { write("Su: That monster body is presently inhabited.\n"); return 1; } this_player()->query_link()->set("tmp_body", ob); ret = this_player()->query_link()->switch_body(); if(!ret) { write("Su: Could not transfer into " + name + ".\n"); return 1; } ob->clear_monster(); seteuid( (string)this_player()->link_data("name") ); export_uid(ob); seteuid(getuid()); ob->init_setup(); old->set_link(0); old->quit(); write("Transfer complete.\n> "); return 1; } mapping query_active() { return active; } int help() { write("Usage: su [user]\n\n" + "The su command allows a user to change from their present character\n" + "to another, either a fresh version of the present character or a new\n" + "version of another character (provided you know the password). It is\n" + "equivalent to logging out and back in again, but quicker. With an\n" + "argument, su prompts you for the requested user's password, and if\n" + "answered correctly, you will be polymorphed into that user. Without\n" + "an argument, or if you pass your own character's name as an argument,\n"+ "you will be transfered into a new copy of your present character.\n"); return 1; }